文章首发博客地址:https://blog.csdn.net/u013277209?viewmode=contents
前言
本篇文章作为吃透Java集合系列第二篇文章,主要探讨Collection接口及其子接口List、Set、Queue。通过本篇文章我们需要明白如下几个问题:
1、Collection的作用?
2、List、Set、Queue接口对Collection接口做了哪些扩展,各自有什么特点?
一:Collection接口
Collection接口是集合层次的根接口,定义了集合的通用操作,所有集合都是在Collection基础上进行扩展的。
先看一下Collection的源码:
/**
 * 集合层次结构中的根接口。一个集合代表一组对象,被称为元素。
 * 一些集合允许重复的元素,而有些则不允许。一些是有序的,另一些是无序的。
 * JDK没有提供这个接口的任何直接的实现:它提供更具体的子接口像 Set和 List实现。
 * 
 * 所有通用的Collection实现类(通常通过其子接口间接实现Collection)应该提供两个“标准”构造函数:
 * void(无参数) 构造函数,它创建一个空集合,以及一个带有Collection类型的单个参数的构造函数,
 * 它创建一个与它的参数具有相同元素的新集合。实际上,后者的构造函数允许用户复制任何集合,生成所需实现类型的等效集合。
 * 没有办法强制执行这个约定(因为接口不能包含构造函数),但是Java平台库中的所有通用Collection实现都符合。
 * 
 * 如果这个集合不支持某个操作的话,调用这些方法可能(但不是必需)抛出 UnsupportedOperationException 
 */
public interface Collection<E> extends Iterable<E> {
    /**
    * 此方法成功完成后,可确保对象包含在集合中。
    * 如果集合被修改,则返回true,如果没有更改,则返回false。
    */
    boolean add(E e)
    /**
    * 将指定集合中的所有元素添加到这个集合
    */
    boolean addAll(Collection<? extends E> c)
    /**
    * 从这个集合中移除指定元素的一个实例
    */
    boolean remove(Object o)
    /**
    * 删除此集合中包含的所有元素的所有元素。
    */
    boolean removeAll(Collection<?> c)
    
    /**
    * 删除满足给定谓词的这个集合的所有元素。
    */
    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
    /**
    * 从这个集合中移除所有不包含在指定集合中的元素的所有元素。
    */
    boolean retainAll(Collection<?> c)
    
    /**
    * 从这个集合中移除所有的元素
    */
    void clear()
    /**
    * 返回此集合中的元素的数目。如果这个集合包含多 Integer.MAX_VALUE元素,返回 Integer.MAX_VALUE。
    */
    int size();
    
    /**
    * 如果此Collection不包含元素,则返回true
    */
    boolean isEmpty()
   
    /**
    * 如果集合包含指定元素,返回 true。
    */
    boolean contains(Object o)
    /**
    * 返回 true如果这个集合包含指定集合的所有元素。
    */
    boolean containsAll(Collection<?> c)
    
    /**
    * 返回一个包含此集合中包含的所有元素的新数组。
    * 如果实现已经排序了元素,它将以与迭代器返回的顺序相同的顺序返回元素数组。
    * 返回的数组不反映集合的任何更改。 即使底层数据结构已经是一个数组,也创建一个新数组。
    */
    Object[] toArray()
    
    /**
    * 返回包含此集合中包含的所有元素的数组。 如果指定的数组足够大以容纳元素,则使用指定的数组
    * 否则将创建相同类型的数组。 如果使用指定的数组并且大于此集合,则Collection元素之后的数组元素将设置为null。
    */
    <T> T[] toArray(T[] a)
   
    /**
    * 重写Object中的equals方法
    */
    boolean equals(Object o)
    
    /**
    * 重写Object中的hashCode方法
    */
    int hashCode()
    
    /**
    * 返回可用于访问此Collection所包含的对象的Iterator实例。 没有定义迭代器返回元素的顺序。
    * 只有当Collection的实例具有定义的顺序时,才能按照该顺序返回元素。
    */
    Iterator<E> iterator()
    
    /**
    * 返回一个并行迭代器类Spliterator
    */
    default Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, 0);
    }
    
    /**
    * 这个集合中的元素的顺序 Stream
    */
    default Stream<E> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
    
    /**
    * 返回一个可能并行 Stream与集合的来源。
    */
    default Stream<E> parallelStream() {
        return StreamSupport.stream(spliterator(), true);
    }
- Collection接口是Java语言中最基本的集合接口,在JDK中没有直接提供Collection接口的具体实现类,Collection的功能实现类主要是对它的三个更具体的子接口List、Set和Queue的具体实现类。但是在Collection接口中定义了一套通用操作的实现方法和命名规则。
- List、Set、Queue接口都继承自Collection并定义了各自不同的方法对其扩展。
二:List接口
List接口扩展了Collection,可以根据下标index对元素进行操作,每个元素都有唯一一个下标对应。
添加了功能更强大的ListIterator迭代器,可以沿任一方向遍历List,并且在遍历期间还可以修改List
/** 
 * List是维护其元素的排序的集合。 List中的每个元素都有一个索引。 因此,每个元素可以被其索引访问,第一个索引为零。 
 * 通常,与集合相比,List允许重复元素,其中元素必须是唯一的。
 * 有序集合(也称为<i>序列</ i>)。 该接口的用户可以精确控制每个元素插入到列表中的哪个位置。 
 * 用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。
 * 
 * 列表允许重复元素,也允许null元素插入
 */  
public interface List<E> extends Collection<E> {  
    /**
     * List作为Collection的子接口提供了Collection接口定义的方法 
     * 这些方法在Collection源码中已经分析过了,就不在说明了 
     */  
    //增
    boolean add(E e); 
    boolean addAll(Collection<? extends E> c); 
    //删
    boolean remove(Object o); 
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter)  
    void clear(); 
    //查
    int size();  
    boolean isEmpty();
    boolean contains(Object o);
    boolean containsAll(Collection<?> c);
    //转数组
    Object[] toArray();  
    <T> T[] toArray(T[] a);  
    //重写Object方法
    boolean equals(Object o);  
    int hashCode();
    //迭代器 
    Iterator<E> iterator();  
    default Spliterator<E> spliterator()
    
    //同时List接口定义了一些自己的方法来实现“有序”这一功能特点 
    /** 
     *返回列表中指定索引的元素
     */  
    E get(int index);  
    /** 
     *设定某个列表索引的值  
     */  
    E set(int index, E element);  
    /** 
     *在指定位置插入元素,当前元素和后续元素后移 
     *这是可选操作,类似于顺序表的插入操作 
     */  
    void add(int index, E element); 
    /**
    * 在指定位置插入指定集合中的元素,当前元素和后续元素后移
    */ 
    boolean addAll(int index, Collection<? extends E> c);  
    /** 
     * 删除指定位置的元素(可选操作)
     */  
    E remove(int index);  
    /** 
     * 获得指定对象的最小索引位置,没有则返回-1
     */  
    int indexOf(Object o);  
    /**
     * 获得指定对象的最大索引位置,可以知道的是若集合中无给定元素的重复元素下 
     * 其和indexOf返回值是一样的
     */  
    int lastIndexOf(Object o);  
    /**
     * 一种更加强大的迭代器,支持向前遍历,向后遍历 
     * 插入删除操作,此处不解释
     */  
    ListIterator<E> listIterator();  
    ListIterator<E> listIterator(int index);  
    /** 
     * 返回索引fromIndex(包括)和toIndex(不包括)之间的视图。
     */  
    List<E> subList(int fromIndex, int toIndex);  
}  
List集合特点
- 内部元素是有序的 ,集合中每个元素都有其对应的顺序索引。
- 元素是可以重复的 ,因为它可以通过索引来访问指定位置的集合元素。
- List接口有3个常用的实现类,分别是ArrayList、LinkedList、Vector。
三:Set接口
Set接口完全继承了Collection,在Collection基础上并没有什么改动,但是增加了一个约定:不包含重复元素的集合!
接下来我们看一下源码:
/**
 * Set是不允许重复元素的数据结构。
 */
public interface Set<E> extends Collection<E> {
    /**
     * Set作为Collection的子接口提供了Collection接口定义的方法 
     * 这些方法在Collection源码学习中已经分析过了,就不在说明了 
     */  
   //增
    boolean add(E e); 
    boolean addAll(Collection<? extends E> c); 
    //删
    boolean remove(Object o); 
    boolean removeAll(Collection<?> c);
    boolean retainAll(Collection<?> c);
    default boolean removeIf(Predicate<? super E> filter)  
    void clear(); 
    //查
    int size();  
    boolean isEmpty();
    boolean contains(Object o);
    boolean containsAll(Collection<?> c);
    //转数组
    Object[] toArray();  
    <T> T[] toArray(T[] a);  
    //重写Object方法
    boolean equals(Object o);  
    int hashCode();
    //迭代器 
    Iterator<E> iterator();  
    default Spliterator<E> spliterator()
}
Set内部元素是无序的,元素是不可以重复的
四:Queue接口
1、Queue是在处理之前保存元素的集合。除了基本的Collection操作外,Queue还提供额外的插入、删除和检查操作
2、每个Queue方法都有两种形式:(1)如果操作失败则抛出异常,(2)如果操作失败,则返回特殊值(null或false,具体取决于操作),接口的常规结构如下表所示。
| 抛出异常 | 返回特殊值 | |
|---|---|---|
| 插入 | add(e) | offer(e) | 
| 删除 | remove() | poll() | 
| 检查 | element() | peek() | 
/**
 * Queue是在处理之前保存元素的集合。除了基本的Collection操作外,Queue还提供额外的插入、删除和检查操作
 * 每个Queue方法都有两种形式:(1)如果操作失败则抛出异常,
 * (2)如果操作失败,则返回特殊值(null或false,具体取决于操作),接口的常规结构如下表所示。
 * 插入操作的后一种形式是专为使用有容量限制 Queue实现;在大多数实现中,插入操作不会失败。
 * 
 * |          | 抛出异常         | 返回特殊值             |
 * |插入      | add(e)          | offer(e)              |
 * |删除      | remove()        | poll()                |
 * |检查      | element()       | peek()                |
 * 
 * 队列通常(但不一定)以FIFO(先进先出)方式对元素进行排序,优先级队列除外,
 * 它们根据元素的值对元素进行排序 — 有关详细信息,请参阅“对象排序”部分。
 * 无论使用什么排序,队列的头部都是通过调用remove或poll移除的元素。
 * 在FIFO队列中,所有新元素都插入队列的尾部,其他类型的队列可能使用不同的放置规则,
 * 每个Queue实现都必须指定其排序属性。
 *
 * Queue实现可以限制它所拥有的元素数量,这样的队列被称为有界,java.util.concurrent中的某些Queue实现是有界的,但java.util中的实现不是。
 * 可不只有抛出unchecked异常添加元素。的offer方法设计时使用的失败是正常的,
 * 而不是特殊的情况,例如,固定容量(或“有界”)队列。的remove()和poll()方法移除并返回队列的头部。
 * 从队列中删除的是队列的排序策略的函数,它不同于从“实现”到“实现”的功能。的remove()和poll()方法
 * 只是他们的行为当队列为空的不同的remove()方法抛出一个异常,而poll()方法返回null。
 *
 * Queue从Collection继承的add方法插入一个元素,除非它违反了队列的容量限制,
 * 在这种情况下它会抛出IllegalStateException。offer方法,仅用于有界队列,
 * 与add不同之处仅在于它通过返回false来表示插入元素失败。
 *
 * remove和poll方法都移除并返回队列的头部,确切地移除哪个元素是队列的排序策略的函数,
 * 仅当队列为空时,remove和poll方法的行为才有所不同,在这些情况下,
 * remove抛出NoSuchElementException,而poll返回null。
 *
 *element和peek方法返回但不移除队列的头部,它们之间的差异与remove和poll的方式完全相同:如果队列为空,则element抛出NoSuchElementException,而peek返回null。
 * 队列实现通常不允许插入null元素,为实现Queue而进行了改进的LinkedList实现是一个例外,
 * 由于历史原因,它允许null元素,但是你应该避免利用它,因为null被poll和peek方法用作特殊的返回值。
 *队列实现通常不定义equals和hashCode方法的基于元素的版本,而是从Object继承基于标识的版本。
 * Queue接口不定义阻塞队列方法,这在并发编程中很常见,这些等待元素出现或空间可用的方法在java.util.concurrent.BlockingQueue接口中定义,该接口扩展了Queue。
 *
 */
public interface Queue<E> extends Collection<E> {
    /**
     * 将指定的元素插入到此队列中,如果不违反容量限制立即执行此操作 
     * 成功后返回true,如果当前没有可用空间,则抛出IllegalStateException。
     */
    boolean add(E e);
    /**
     * 如果在不违反容量限制的情况下立即执行,则将指定的元素插入到此队列中。 
     * 当使用容量限制队列时,此方法通常优于add(E) ,这可能无法仅通过抛出异常来插入元素。 
     * 成功返回true,失败返回false
     */
    boolean offer(E e);
    /**
     * 检索并删除此队列的头。 此方法与poll不同之处在于,如果此队列为空,它将抛出异常。
     */
    E remove();
    /**
     * 检索并删除此队列的头,如果此队列为空,则返回 null 。
     */
    E poll();
    /**
     * 检索,但不删除,这个队列的头。 此方法与peek的不同之处在于,如果此队列为空,它将抛出异常。
     */
    E element();
    /**
     * 检索但不删除此队列的头部,如果此队列为空,则返回 null 。
     */
    E peek();
}
Queue接口特点:
- 先进先出的数据结构,即从容器的一端放入对象,从另一端取出,并且对象放入容器的顺序与取出的顺序是相同的。
- 虽然Queue接口继承Collection接口,但是Queue接口中的方法都是独立的,在创建具有Queue功能的实现时,不需要使用Collection方法。