集合框架
集合
集合在我们的日常开发中所使用的次数简直太多了,你已经把它们都用的熟透了,但是作为一名合格的程序员,你不仅要了解它的基本用法,你还要了解它的源码;存在即合理,你还要了解它是如何设计和实现的,你还要了解它的衍生过程。
这篇博客就来详细介绍一下 Collection这个庞大集合框架的家族体系和成员,让你了解它的设计与实现。
是时候祭出这张神图了
爷爷辈接口——Iterator
Iterable 接口
List<Object> list = new ArrayList(); |
除了实现此接口的对象外,数组也可以用for-each循环遍历:
Object[] list = new Object[10]; |
顶层接口
Collection
是一个顶层接口,主要用来定义集合的约定
List
接口也是一个顶层接口,继承了Collection,同时也是ArrayList
、LinkedList
等集合元素的父类
Set
接口与List接口同级别,也继承了Collection,提供了额外的规定。对add、equals、hashCode方法提供了额外的标准。
Queue
是List、Set接口以外的Collection的三大接口之一。Queue的设计用来在处理之前保持元素的访问次序。除了Collection基础的操作之外,队列提供了额外的插入,读取,检查操作。
SortedSet
接口直接继承于Set接口,使用Comparable
对元素进行自然排序或者使用Comparator
在
创建时对元素提供定制的排序规则。set的迭代器将按升序元素顺序遍历集合。
Map
是一个支持key-value
存储的对象,Map不能包含重复的key,每个键最多映射一个值。这个接口代替了Dictionary类,Dictionary是一个抽象类而不是接口。
ArrayList
ArrayList 是实现了List接口的可扩容数组(动态数组),内部是在数组的基础上实现的
ArrayList可以替代Vector,但是ArrayList不是线程安全的容器。当有多个线程中至少有两个修改了ArrayList的结构,就会导致线程安全问题, 可以使用线程安全的List替代:
Collections.synchronizedList
线程安全:当多个线程访问某个方法时,不管通过怎样的调用方式或者无论线程如何交替的执行,在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的 |
ArrayList支持fail-fast机制
fail-fast 机制是Java集合(Collection)中的一种错误机制。 在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的结构进行了修改(增加、删除),则会抛出Concurrent Modification Exception(并发修改异常) |
Vector
ArrayList内部是在数组的基础上实现的,Vector是一个线程安全的容器,对内部每个方法,避免出现线程安全问题的解决方法都是直接加锁。
这种方法的缺点是同步开销大,访问效率远低于ArrayList
在扩容时ArrayList扩容后数组长度只增加50%,而Vector的扩容会扩大一倍长度。
LinkedList类
- LinkedList是一个双向链表,允许存储任何元素(包括null),它有以下特性:
- LinkedList所有操作都是双向的,索引到链表的操作将遍历从头到尾,从距离近的那一头开始遍历
- 只有这个链表外部加锁后,通过LinkedList实现的方法才是线程安全的,如果多个线程并发访问链表,并且至少其中一个线程修改了链表结构,这个链表必须进行外部加锁,或者使用:
List list = Collections.synchronizedList(new LinkedList(...))
Stack
stack-堆栈,是后入先出容器。继承了Vector类,提供了通常用的push和pop操作,以及在栈顶的peek方法,测试stack是否为空的empty方法,和一个寻找与栈顶距离的search方法
第一次创建栈,不包含任何元素。一个更完善,可靠性更强的LIFO栈操作由Deque接口和他的实现提供:
Deque<Integer> stack = new ArrayDeque<Integer>()
HashSet
HashSet是Set接口的实现类,由哈希表支持(实际上HashSet是HashMap的一个实例),不能保证集合的迭代顺序,允许有null元素
- 这个实现不是线程安全的
- 需要外部加锁,或者使用Collections.synchronizedSet()方法重写
- 支持fail-fast机制
等等