Java集合源码分析02----Collection集合

目录

 

Collection框架综述

Collection接口

Set接口

List接口

Queue接口

迭代器

———–参考《Thank In Java》

Collection框架综述

Collection是一个接口,分为常见的两部分:List和Set,以及在并发编程常用的Queue.

其中AbstractCollection抽象类实现了接口Collection中大部分的方法,AbstractList和AbstractSet两个抽象类又直接继承了AbstractCollection,而基本上所有的List和Set接口实现类都分别继承AbstractList和AbstractSet类,这样减少实现类中代码的重复,而Queue接口的大部分实现类继承了AbstractCollection。

List集合特点是元素是有序的,并且允许元素重复;Set集合不能有重复的元素;Queue按照排队规则来确定对象输出的顺序(通常与它们被插入的顺序相同)。

《Java集合源码分析02----Collection集合》

Collection接口

Collection接口是Collection继承体系中根接口,定义了获取集合大小,添加元素,删除元素,清空,判空以及迭代元素的迭代器等方法。

//返回当前存储到集合中元素个数
int size(); 
//collection中不包含任何元素,返回true
boolean isEmpty();
//collection包含了指定了元素,返回true.
boolean contains(Object o);
//返回一个用于访问集合中每个元素的迭代器
Iterator<E> iterator();
//返回包含collection所有元素的数组
Object[] toArray();
//返回包含collection所有元素的数组,并且指定了数组的类型
<T> T[] toArray(T[] a);
//添加指定的元素,返回是否添加成功
boolean add(E e);
//移除指定的元素,返回是否移除成功
boolean remove(Object o);
//判断collection里面是否包含集合c中所有元素
boolean containsAll(Collection<?> c);
//将集合c中所有元素添加到collection中
boolean addAll(Collection<? extends E> c);
//移除collection中那些也包含在集合c中元素
boolean removeAll(Collection<?> c);
//保留此collection中那些在集合c中包含的元素
boolean retainAll(Collection<?> c);
//移除此collection中的所有元素
void clear();
//collection与指定对象o是否相等
boolean equals(Object o);
//返回此collection的hashcode值
int hashCode();
//jdk1.8中加入的内容
default Spliterator<E> spliterator() {}
default Stream<E> stream() {}
default Stream<E> parallelStream() {}
default boolean removeIf(Predicate<? super E> filter) {}

Set接口

Set接口中的方法与Collection完全一样的,没有添加任何的额外的功能。实际上Set就是Collection,只是表现了不同的行为(是多态与继承的典型应用)。Set不会保存重复的元素,允许保存null,并且只能有一个。

Set接口常见的实现类:

1)HashSet:使用散列函数的存储方式,HashSet按照哈希算法来存储集合的元素,具有很好的存取和查找性能,非线程安全的。HashSet依赖HashMap实现的,集合中元素是无序的(元素插入和输出的顺序不一致)。HashSet主要是为了快速查找而设计的,存入HashSet的元素必须要定义HashCode()方法。

2)LinkedHashSet:继承自HashSet,底层依赖LinkedHashMap实现的, 使用了散列函数 ,但LinkedHashSet使用了链表来维护元素的插入位置,所以集合中元素是有序的,可以按照元素的添加顺序来访问集合中的元素。

3)TreeSet:将元素存储在了红黑数数据结构中,继承自SortedSet接口,存储到TreeSet中的元素需要实现Comparable接口,重写CompareTo()方法,TreeSet会按照排序顺序维护元素(即CompareTo()实现方式,如降序或者升序)。

4)EnumSet是枚举类型元素集合的高效实现,由于枚举类型只有有限个个数,所以EnumSet内部用位序列(位向量)实现。这种存储形式比较高效,占用内存比较小,运行效率比较好。EnumSet提供了很多便捷的静态方法。

List接口

List接口继承自Collection接口,在Collection的基础上添加了其他方法,包含在指定索引位置上添加元素,删除元素,替换元素,获取元素的索引位置以及迭代List集合的迭代器等方法。List可以保存重复的元素,允许保存多个null。List集合是有序的,集合中每个元素都有其对应的索引位置,可以通过索引位置来访问指定位置的元素,第一个索引位置是0。

Collection接口中方法省略
...
//返回list中指定索引的元素
E get(int index);
//用指定的元素替换指定索引上的元素
E set(int index, E element);
//list指定索引上插入指定元素
void add(int index, E element);
//添加集合c中的元素到list指定的索引
boolean addAll(int index, Collection<? extends E> c);
//移除list中指定索引上元素
E remove(int index);
//返回list中第一次出现指定元素的索引,如果不包含该元素,将返回-1.
int indexOf(Object o);
//返回list中最后出现的指定元素的索引,如果不包含该元素,将返回-1.
int lastIndexOf(Object o);
//返回此list的元素迭代的迭代器.
ListIterator<E> listIterator();
//返回此list的元素的迭代的迭代器,从指定位置开始.
ListIterator<E> listIterator(int index);
//返回从list的fromIndex(包含)到toIndex(不包含)之间的元素
List<E> subList(int fromIndex, int toIndex);
//jdk1.8添加的内容
default void replaceAll(UnaryOperator<E> operator)
default void sort(Comparator<? super E> c)

List接口的实现类常见有如下:

1)ArrayList:底层是一个动态数组,随机访问速度比较快,但是在ArrayList中插入和移除元素时较慢。它是非线程安全的。

2)LinkedList:继承了Deque接口,底层是一个双向链表的结构,在LinkedList中插入和删除元素代价比较低(这点比ArrayList更加高效),但随即访问操作方面效率比较低。经常被当做堆栈,队列或者双端队列使用,它是非线程安全的。

3)Vector:与ArrayList一样,底层也是动态数组,但是Vector是线程安全的,并且Vector相比ArrayList,没有实现java.io.Serializable接口,所以不支持序列化。

4)Stack:是“栈”,继承自Vector,是先进后出(LIFO)的容器(有时称为叠加栈),即压人栈的第一个元素,最后一个弹出栈。

Queue接口

Queue,即队列,是一个典型先进先出的容器(FIFO),即从容器的一端放入元素,然后从另外一端取出元素。放入队列中的顺序与取出元素的顺序是一样的。队列在并发编程中比较重要。

//向队列中插入指定的元素,成功返回true,如果没有空间将抛出异常
boolean add(E e);
//向队列中插入指定的元素
boolean offer(E e);
//移除队列头部的元素,队列我空时将抛出异常
E remove();
//移除队列头部的元素,队列为空时返回null
E poll();
//获取队列头部的元素,队列为空时将抛出异常
E element();
//获取队列头部的元素,队列为空时返回null
E peek();

关于Queue接口中几个方法在操作失败时差异说明:

1)add(e),remove(),element()方法在对集合操作失败时将会抛出异常。

2)offer(e),poll(),peek()方法在对集合操作失败时将返回特殊值。

队列操作抛出异常(失败情况下)返回特殊值(失败情况下)
插入add(e)offer(e)
移除remove()poll()
检查element()peek()

1)PriorityQueue:并不是一个标准的先进先出的队列,先进先出队列规则表明了下一个元素应该是等待时间最长的元素。但PriorityQueue可以定义优先级,声明下一个弹出的元素是最需要的元素(优先级最高)。当向PriorityQueue插入一个对象时,会在队列中进行排序,默认的排序方法使用的是对象在队列中的自然顺序,但可以通过提供Comparator来修改这个顺序。

2)Deque:接口表示的是一个双向队列(双端队列),可以在头部和尾部任何一端添加和删除元素,不支持在队列中间插入元素。因此Deque的实现类即可以当成队列使用,也可以当成栈使用。

迭代器

在java.lang包下面有一个接口Iterable,里面包含方法iterator(),返回类型是Iterator接口类型,Collection接口继承Iterable接口,Collection接口实现类实现了Iterator()方法,所以Collection集合体系可以使用迭代器或者foreach循环进行遍历。

public interface Iterable<T> {
    Iterator<T> iterator();
}

Iterator接口如下

public interface Iterator<E> {
    //如果仍有元素可以迭代,返回true
    boolean hasNext();
    //返回迭代下一个元素
    E next();
    //删除迭代器刚访问过的元素
    default void remove(){}
    //jdk1.8添加的内容
    default void forEachRemaining(Consumer<? super E> action) {}
}

迭代器的工作就是为了遍历并选择序列中的对象,而不需要知道数据的底层结构。迭代器是轻量级对象,创建它的代价较小。

    1)Iterator迭代器只能单向移动,使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回第一个元素。

    2)使用next()获取序列中的下一个元素。

    3)使用hasNext()检查序列中是否还有元素。

    4)使用remove()将迭代器上次访问的元素删除。

ListIterator接口继承自Iterator接口,在接口List中,ListIterator()方法返回的是ListIterator对象,专门用于遍历List集合。

public interface ListIterator<E> extends Iterator<E> {
    //正向遍历,存在元素,返回true
    boolean hasNext();
    //返回列表中下一个元素
    E next();
    void remove();
    //逆向遍历,如果存在元素,返回true
    boolean hasPrevious();
    //返回列表中前一个元素
    E previous();
    //返回对next()调用所返回元素的索引
    int nextIndex();
    //返回对previous调用所返回的元素索引
    int previousIndex();
    //用指定元素替换next或者previous上次访问的元素
    //如果在next或者previous上次调用之后列表结构被修改,将抛出异常。
    void set(E e);
    //将指定的元素插入列表中
    void add(E e);
}

ListIterator接口定义的方法可以看出,

    1)可以实现双向移动( 向前或者向后遍历)

    2)产生相对迭代器在列表中指向的当前位置的前一个和后一个元素的索引。

    3)可以使用set()方法替换它访问过的最后一个元素。

    4)可以使用add()方法在next()方法返回的元素之前或者previous()返回的元素之后插入一个元素。

    5)通过调用List集合中listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过listIterator(n)方法创建一个一开始就指向列表索引n的元素处的ListIterator。

关于迭代器需要注意:当线程A通过Collection集合中的方法iterator()方法获取遍历集合的迭代器时,如果此时集合的内容被其他线程修改,线程A将会抛出ConcurrentModificationException异常

 

 

    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/lili13897741554/article/details/83501735
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞