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

一、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库中的具体集合

Java库中的具体集合
                ——摘自《Core Java》

参考连接:
正确重写hashCode的办法
ArrayList源代码分析
Iterator的remove()和Collection的remove()
Arrays.asList()注意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值