您的位置:首页 > 编程语言 > Java开发

Java库中的常用集合(Collection/List/Set/Map)

2016-11-13 20:25 746 查看

一、Collection<E> 接口

1.1、常用方法

/*
*增删操作
*/
boolean add(E e)
boolean remove(Object o)

/*
*集合操作
*/
//对于Set接口就是求并集,对于List接口就是将两列表连接起来
boolean addAll(Collection<? extends E> c)
//对于Set接口就是求差集
boolean removeAll(Collection<?> c)
//对于Set接口就是求交集
boolean retainAll(Collection<?> c)

/*
*查找某一个或几个元素在集合中是否存在
*/
boolean contains(Object o)
boolean containsAll(Collection<?> c)


以上方法都会涉及集合元素的比较,这些比较都是通过调用显式参数的equals()方法来完成的,所以需要重写equals()方法。

以上方法的隐式参数和显式参数都只要求实现了Collection接口即可,所以可以出现隐式参数和显式参数一者为Set,一者为List的情况(但这种情况,在实现正确的equals()方法的约束下,永远返回false)。

equals()方法重写示例:

/*
*情形一:如果子类能够拥有自己的相等概念,则对称性需求将强制采用getClass进行检测
*/
class Employee{
public String name;
public int age;
public double[] bwh;
//...
@Override
public boolean equals(Object obj){ //equals()方法的入参必须为Object类型
if(this ==  obj) return true;
if(obj == null) return false;

if(getClass() != obj.getClass()) return false;
Employee other = (Employee)obj;

return Objects.equals(name,other.name) //引用类型比较
&& age == other.age                //基本类型比较
&& Arrays.equals(bwh,other.bwh);   //数组比较
}
}

/*
*情形二:如果由超类决定相等的概念,那么就可以使用instanceof进行检测,这样可以在不同子类的对象之间进行相等的比较
*/
class Employee extends SuperClassName{
public String name;
public int age;
public double[] bwh;
//...
@Override
public boolean equals(Object obj){
if(this ==  obj) return true;
if(obj == null) return false;

if(!(obj instanceof SuperClassName)) return false;
SuperClassName other = (SuperClassName)obj;

//superName、superAge等是父类的属性
return Objects.equals(superName,other.superName)
&& superAge == other.superAge
&& Arrays.equals(superbwh,other.superbwh);
}
}


重写equals()方法的同时,也必须重写hashCode()方法:

class Employee{
public String name;
public int age;
public double height;
public double[] bwh;
//...
@Override
public int hashCode(){
int c = 7;    //最好为质数。防止键的集聚
return c * Objects.hashCode(name)        //引用类型的哈希值
+ c * age                           //int型的哈希值
+ c * new Double(height).hashCode() //double型的哈希值
+ c * Arrays.hashCode(bwh);         //数组的哈希值
}
}


当equals()方法返回true时,两个对象的hashcode也必须相同;当equals()方法返回false时,两个对象的hashcode在大多数情况是不同的,在少数情况下相同。

集合类判断两个对象是否相等,是先判断hashcode是否相等,再判断equals()返回值是否为ture,只有两者都相等时,才认为该两个对象是相等的。所以若两个相同的对象有不同的hashcode,就会将两个相同的对象插入到Set或Map中。

所谓散列冲突,是指集合类在判断两个对象是不同的之后,将两者的hashcode经过运算,发现两者在桶(bucket)中的位置是相同的。两者的hashcode不相同时有可能出现散列冲突,两者的hashcode相同时一定会出现散列冲突。所以就算不同的对象有相同的hashcode,也不会影响集合类的正常运行。

1.2、迭代器方法 Iterator<E> iterator()

迭代器使用示例:

Collection<String> c = new ArrayList<String>();
Iterator<String> iter = c.iterator();
while(iter.hasNext()){
String element = iter.next();
if(...){
iter.remove();
}
}


只有对自然有序的集合使用迭代器添加元素才有实际意义。

                ——摘自《Core Java》

所以Collection接口的迭代器没有add()方法,而List接口的迭代器才有add()方法。

在执行 Iterator iter = c.iterator() 时,相当于生成了该集合的一个迭代器实例,若使用该迭代器实例以外的方法修改集合(包括集合自身的方法和其它迭代器实例的方法),就会抛出Concurrent ModificationException异常。

迭代器在add或remove时,会额外改变自己独有的游标,所以在遍历集合时进行增删操作不会出现误操作。

迭代器每次执行next()方法时,都会重新复制当前集合,所以迭代器可以实时反应集合的变化。

二、List<E> 接口

2.1、常用方法

//增
boolean add(E e)
void add(int index, E e)
//删
boolean remove(Object o)
E remove(int index)
//改
E set(int index, E element)
//查
E get(int index)
int indexOf(Object o)
//获取子集合
List<E> subList(int fromIndex, int toIndex)
//获取迭代器
ListIterator<E> listIterator()
ListIterator<E> listIterator(int index)


2.2、迭代器方法 ListIterator<E> listIterator()

比Iterator多出来的方法:

//Iterator只有删和查的操作,ListIterator还增加了增和改的操作
void add(E e)
void set(E e)


三、Set<E> 接口

3.1、常用方法

//增
boolean add(E e)
//删
boolean remove(Object o)


四、Map<K,V> 接口

List接口、Set接口是继承自Collection接口的,而Map接口与Collection接口是平行的关系。

4.1、常用方法

//增、改
V put(K key, V value)
void putAll(Map<? extends K,? extends V> m)
//查
V get(Object key)
boolean containsKey(Object key)
boolean containsValue(Object value)
//删
V remove(Object key)


4.2、Map的视图

三种视图:

//键值对集
Set<Map.Entry<K,V>> entrySet()
//键集
Set<K> keySet()
//值集(不是集)
Collection<V> values()


视图使用示例:

Map<String,Employee> staff = new HashMap<String,Employee>();
for(Map.Entry<String,Employee> entry : staff.entrySet()){
String key = entry.getKey();        //取键
Employee value = entry.getValue();  //取值
//...
entry.setValue(e); //重新设值
}


注意点:

entrySet()和keySet()返回的Set,既不是HashSet也不是TreeSet,而是实现了Set接口的某个其它类的对象。同时Set接口扩展了Collection接口,因此可以与使用任何集合一样使用entrySet()和keySet()返回的Set。

                ——摘自《Core Java》

values()的返回类型是Collection而不是Set,是因为所谓“值集”并不是集,因为有可能重复。

五、类型转换

5.1 不同集合类之间的转换

//通过各自的构造函数
ArrayList(Collection<? extends E> c)
LinkedList(Collection<? extends E> c)
HashSet(Collection<? extends E> c)


关键点在于这些构造函数的入参都仅仅要求是Collection,So elegant!

5.2 集合类与数组之间的转换

/*
*数组转换为集合类
*/
String[] arr ={"a","b","c"};
List<String> list = Arrays.asList(arr); //此处list不可修改
//或直接 List<String> list = Arrays.asList("a","b","c");

List<String> arrList = new ArrayList<String>(list);//此处arrList可修改

/*
*集合类转换为数组
*/
List<String> arrList = new ArrayList<String>();
String[] arr = new String[arrList.size()];
arrList.toArray(arr);


六、Java库中的具体集合



                ——摘自《Core Java》

参考连接:

正确重写hashCode的办法

ArrayList源代码分析

Iterator的remove()和Collection的remove()

Arrays.asList()注意
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 对象