首页 > 技术文章 > Java 集合:(二) Collection接口

niujifei 2021-04-14 13:21 原文

一、Collection 接口概述

    1、Collection 接口单列集合类的根接口,用于存储一系列符合某种规则的元素,它是 List、Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。
    2、JDK不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set和List)实现。
 
    3、在 Java5 之前,Java 集合会丢失容器中所有对象的数据类型,把所有对象都当成 Object 类型处理;从 JDK 5.0 增加了泛型以后,Java 集合可以记住容器中对象的数据类型。
    Collection 接口又是集合层次中的根接口,最常用的 List 和 Set  接口都继承自它。

    List 的特点是 元素有序、元素可重复。主要实现类有 java.util.ArrayList 和 java.util.LinkedList。

      Set 的特点是 元素无序、而且不可重复。主要实现类有 java.util.HashSet 和 java.util.TreeSet。

    它们的继承结构如下(常用部分):
    

    Collection 接口的方法描述如下:
    

 

    注意:这里是以JDK8版本来进行学习的。

二、常用方法

  1、常用方法

add(Object e):将元素e添加到集合collection中
addAll(Collection coll):将coll集合中的元素添加到当前的集合中

size():获取有效元素的个数

clear():清空集合元素

isEmpty():判断当前集合是否为空

是否包含某个元素:通过元素的equals方法来判断比较
contains(Object obj):判断当前集合中是否包含obj
containsAll(Collection coll):判断形参coll中的所有元素是否都存在于当前集合中

boolean remove(Object obj) : 通过元素的equals方法判断是否是要删除的那个元素。 只会删除找到的第一个元素
removeAll(Collection coll):差集:从当前集合中移除coll中所有的元素

boolean retainAll(Collection c): 把交集的结果存在当前集合中,不影响c

equals(Object obj):要想返回true,需要当前集合和形参集合的元素都相同

hashCode():返回当前集合对象的哈希值,返回该集合的哈希值,注意重写 equals 方法时必须要重写该方法,以满足 Object.hashCode 方法的规定;

Object[] toArray():转成对象数组
<T> T[] toArray(T[] a) 根据指定类型转成数组,可以指定数组的类型

iterator(): 返回迭代器对象,用于集合遍历

    注意:向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals().

 

  2、JDK8新增方法

removeIf(Predicate<? super E>):从该集合中移除满足指定条件的元素,其中 Predicate 是 JDK1.8引入的函数式操作,即传入的参数是一个方法

spliterator():可分割迭代器,用于并行遍历集合中的元素(iterator()方法是顺序遍历)

stream()&parallelStream()JDK1.8引入的流(Stream)式数据处理,分别表示串行流和并行流

forEach(consumer<? super T>)这是继承自 Iterable 接口的方法,该方法也是 JDK1.8引入的,提供遍历集合元素的函数式操作

  

三、Collection接口及子接口

  其中,红色的为 接口,其他的为具体的实现类。

 

  1、Collection接口

    Collection作为一个集合类的顶层接口,他没有直接的子类实现,而是通过实现它的子接口来实现集合容器。Collection的特点是作为一个容器,他可以轻松的帮用户实现数据存储,动态扩容,还有方便的元素遍历和快速的增删改查等操作,这些特点都在接口定义的方法中一一体现出来,相比我们用array来存储数据方便不少。
    Collection的子接口主要是三大类分别是List,Set和Queue。这三个接口各有特点。

  2、List 子接口

    List 是一个顺序存放的容器,他会保存元素的插入顺序,当然元素也可以通过下标位置直接插入和删除。List容器同时允许重复的元素插入和多个null元素。List提供了一个特殊的iterator,叫做ListIterator,这个接口在下文中也有所描述,可以进行双向遍历元素。

  3、Set子接口

    Set集合最大的特点是元素不能重复,所有元素都是唯一的存在。Set集合不保证维护元素的顺序。

  4、Queue 子接口

    顾名思义就是队列,队列最大的特点就是FIFO先进先出,与之对应的有栈Stack后进先出。Queue在Collection的基础之上又新增加了几个方法:
    offer(E e)与add方法类似,但是当容器存量超出达到上限以后,会插入失败,而报异常。这个方法推荐使用。
    poll()返回并且删除队列的头元素,如果队列为空,返回null
    element()返回但不删除头元素,如果队列为空,会报异常。
    peek()返回但不删除头元素,如果队列为空,返回null。
 

四、Collection 集合的遍历

  1、通过 toArray() 方法

    通过 Collection 的 toArray() 方法,先返回数组,然后遍历数组。

  2、Iterator 迭代器遍历

  3、foreach 遍历(增强 for)

     Java 5时Collection接口继承了java.lang.Iterable接口,因此Collection系列的集合就可以直接使用foreach循环遍历。

    增强 for 循环(for each循环)是JDK 1.5 以后出来的一个高级 for 循环,专门用来遍历数组和集合的。

    它的内部原理其实是个 Iterator 迭代器,所有在遍历的过程中,不能对集合中的元素进行增删操作。

    语法格式

for(元素的数据类型  迭代变量 : Collection集合or数组){ 
  	//写操作代码
}

     注意:它用于遍历 Collection 和数组,通常只进行遍历元素,不要在遍历的过程中对集合元素进行增删操作。

     Demo:

1 public class Demo{
2     public static void main(String[] args) {
3         int[] arr = {3,5,6,87};
4         //使用增强for遍历数组
5         for(int a : arr){//a代表数组中的每个元素
6             System.out.println(a);
7         }
8     }
9 }

 

 

 

 

五、思考

  1、当自己创建一个动态数组类或容器,可以使用 foreach 遍历吗?

   foreach 底层是使用了 Iterator 迭代器。所以需要把当前类实现 Iterable 接口,然后实现iterator() 方法。

   Iterator 也是一个接口,它的实现类,通常在集合(容器) 类中使用内部类实现,并在 iterator() 方法中创建它的对象。

   Demo:

 1 public class MyArrayList implements Iterable{ 
 2     //实现迭代器
 3     @Override
 4     public Iterator iterator() {
 5         return new MyItr();
 6     }
 7     // 私有化的内部类
 8     private class MyItr implements Iterator{
 9         private int cursor;//游标
10 
11         @Override
12         public boolean hasNext() {
13             System.out.println("还有下一个");
14             return cursor!=total;
15         }
16 
17         @Override
18         public Object next() {
19             System.out.println("拿到下一个");
20             return data[cursor++];
21         }
22         
23     }
24 }    

  2、如果遍历数组,什么情况下选用foreach,什么情况下选用for循环?

    ① 当如果操作中涉及到 【下标】操作时,用for最好

    ② 当只是查看使用元素的内容,那么选 foreach 更简洁一些

  3、如果遍历Collection系列集合,什么情况下选用foreach,是否能选用 for 循环?

    首先考虑使用foreach,如果该集合也有索引信息的话,也可以通过for来操作,如果没有下标的信息,就不要用for。即,如果该集合的物理结构是数组的,那么可以用for,如果物理结构是链式,那么使用下标操作效率很低。

  4、如果遍历Collection系列集合,什么情况下选用foreach,什么情况下使用Iterator?

    ① 如果只是查看集合的元素,使用foreach,代码会更简洁。

    ② 但是如果要涉及到在遍历集合的同时根据某种条件要删除元素等操作,那么选用Iterator。

 

六、总结

    对容器的顶层接口Collection及其子接口做了介绍,在这个接口的规范下,衍生出了非常多的子类,这些子类都风格迥异,各有千秋。但总体来说就是为了满足对容器内部元素的不同操作,无非就是快速存储,读取遍历,排序等等。

 

 

推荐阅读