1. Java List
1. Java List重要观点
- Java List接口是Java Collections Framework的成员。
- List容许您添加剧复元素。
- List容许您拥有'null'元素。
- List接口在Java 8中有许多默认方法,例如replaceAll,sort和spliterator。
- 列表索引从0开始,就像数组同样。
- List支持泛型(类型的参数化),咱们应尽量使用它。将Generics与List一块儿使用将在运行时避免ClassCastException。
2. Java列表类图
Java List接口扩展了Collection接口。Collection接口 externs Iterable接口。html
一些最经常使用的List实现类是ArrayList,LinkedList,Vector,Stack,CopyOnWriteArrayList。java
AbstractList提供了List接口的骨干实现,以减小实现List的工做量。编程

3. Java List方法
- int size():获取列表中元素的数量。
- boolean isEmpty():检查列表是否为空。
- boolean contains(Object o):若是此列表包含指定的元素,则返回true。
- Iterator <E> iterator():以适当的顺序返回此列表中元素的迭代器。
- Object [] toArray():以适当的顺序返回包含此列表中全部元素的数组
- boolean add(E e):将指定的元素追加到此列表的末尾。
- boolean remove(Object o):今后列表中删除指定元素的第一个匹配项。
- boolean retainAll(Collection <?> c):仅保留此列表中包含在指定集合中的元素。
- void clear():从列表中删除全部元素。
- E get(int index):返回列表中指定位置的元素。
- E set(int index,E element):用指定的元素替换列表中指定位置的元素。
- ListIterator <E> listIterator():返回列表中元素的列表迭代器。
- List <E> subList(int fromIndex,int toIndex):返回指定fromIndex(包含)和toIndex(不包括)之间的此列表部分的视图。返回的列表由此列表支持,所以返回列表中的非结构更改将反映在此列表中,反之亦然。
在Java 8中添加到List的一些默认方法是;api
- default void replaceAll(UnaryOperator <E>运算符):将此列表的每一个元素替换为将运算符应用于该元素的结果。
- default void sort(Comparator <super E> c):根据指定的Comparator引起的顺序对此列表进行排序。
- default Spliterator <E> spliterator():在此列表中的元素上建立Spliterator。
2. ArrayList
1. ArrayList 结构图

ArrayList基于数组实现,是一个动态的数组链表。可是它和Java中的数组又不同,它的容量能够自动增加,相似于C语言中动态申请内存,动态增加内存!
ArrayList继承了AbstractList,实现了RandomAccess、Cloneable和Serializable接口!数组
- 实现了RandomAccess接口,提供了随机访问功能,实际上就是经过下标序号进行快速访问,所以查找效率高。
- 实现了Cloneable接口,即覆盖了函数clone(),实现浅拷贝。
- 实现了Serializable接口,支持序列化,也就意味了ArrayList可以经过序列化传输。
2. ArrayList 重要特色
- 本质实现:Object类型的动态的数组。
- 线程安全:非同步的。
- 列表长度:ArrayList中元素个数用size记录。
- 扩展容量:初始化容量 = 10 ,最大容量不会超过 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8!【Integer.MAX_VALUE = 0x7fffffff,换算成二进制: 2^31 - 1,十进制就是 :2147483647,二十一亿多。一些虚拟器须要在数组前加个 头标签,因此减去 8 。 当想要分配比 MAX_ARRAY_SIZE 大的个数就会报 OutOfMemoryError。】当ArrayList容量不足以容纳所有元素时,ArrayList会从新设置容量:JDK1.6 int newCapacity = (oldCapacity * 3) /2 + 1; JDK1.8 int newCapacity = oldCapacity + (oldCapacity >> 1); 当容量不够时,调用ensureCapacity(int minCapacity)方法调整列表容量,每次增长元素,都要将原来的元素拷贝到一个新的数组中,使用Arrays.copyOf(elementData, newCapacity)拷贝 ,很是之耗时,也所以建议在事先能肯定元素数量的状况下,才使用ArrayList,不然建议使用LinkedList。咱们能够主动调用 ensureCapcity 来增长 ArrayList 对象的容量,这样就避免添加元素满了时扩容、挨个复制后移等消耗。
- 3种构造方法:1)构造一个默认初始容量为10的空列表; 2) 构造一个指定初始容量的空列表; 3) 构造一个包含指定collection的元素的列表,内部是Arrays.copyOf(elementData, size, Object[].class);。
- 5种存储方法:1)set(int index, E element)、2)add(E e)、3)add(int index, E element)、4)addAll(Collection<? extends E> c)、5)addAll(int index, Collection<? extends E> c) 其中3,4,5调用了 System.arraycopy()。
- 2种删除方法:1) remove(int index) ;2)remove(Object o)
- 转换成数组:toArray()方法内部调用Arrays.copyOf(),toArray(T[] a)方法内部若是是部分转换用Arrays.copyOf(),所有转换用 System.arraycopy()。
- 遍历方法:遍历时 get 的效率要 >= 迭代器。
- Fail-Fast机制:ArrayList 不是同步的,因此在并发访问时,若是在迭代器迭代的同时有其余线程修改了 ArrayList, fail-fast 的迭代器 Iterator/ListIterator 会报 ConcurrentModificationException 错。所以咱们在并发环境下须要外部给 ArrayList 加个同步锁,或者直接在初始化时用 Collections.synchronizedList 方法进行包装。也可使用concurrent并发包下的CopyOnWriteArrayList类。快速失败机制经过记录modCount参数来实现。迭代器的快速失败行为应该仅用于检测 bug。
- 序列化:ArrayList实现java.io.Serializable的方式。当写入到输出流时,先写入“容量”,再依次写入“每个元素”;当读出输入流时,先读取“容量”,再依次读取“每个元素”。那为何ArrayList里面的elementData为何要用transient来修饰?不是由于ArrayList不能序列化和反序列化,是由于elementData里面不是全部的元素都有数据,由于容量的问题,elementData里面有一些元素是空的,这种是没有必要序列化的。ArrayList的序列化和反序列化依赖writeObject和readObject方法来实现。能够避免序列化空的元素。序列化size大小的元素。
- 克隆: ArrayList的本质是维护了一个Object的数组,因此克隆也是经过数组的复制实现的,属于浅复制,调用的是Arrays.copyOf()。若是你想要修改克隆后的集合,那么克隆前的也会被修改。那么就须要使用深复制。经过实现对象类的clone方法。
- ArrayList的实现中大量地调用了Arrays.copyof()和System.arraycopy()方法。
- ArrayList基于数组实现,能够经过下标索引直接查找到指定位置的元素,所以查找效率高,但每次插入或删除元素,就要大量地移动元素,插入删除元素的效率低。
- 在查找给定元素索引值等的方法中,源码都将该元素的值分为null和不为null两种状况处理,ArrayList中容许元素为null。
- indexOf和lastIndexOf 查找元素,若元素不存在,则返回-1!
- 适合读数据多的场合。
2. LinkedList
1. LinkedList 结构图

LinkedList是基于链表实现的,从源码能够看出是一个双向链表。除了当作链表使用外,它也能够被看成堆栈、队列或双端队列进行操做。安全
LinkedList不是线程安全的,继承AbstractSequentialList实现List、Deque、Cloneable、Serializable。数据结构
- LinkedList继承AbstractSequentialList,AbstractSequentialList 实现了get(int index)、set(int index, E element)、add(int index, E element) 和 remove(int index)这些函数。这些接口都是随机访问List的。
- LinkedList 实现 List 接口,能对它进行队列操做。
- LinkedList 实现 Deque 接口,即能将LinkedList看成双端队列使用。
- LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
- LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能经过序列化去传输。
2. LinkedList 重要特色
- 本质实现:底层使用一个Node数据结构,有先后两个指针,双向链表实现。
- 线程安全:非同步的。
- 列表长度:LinkedList中元素个数用size记录。
- 列表容量:LinkedList是基于链表实现的,所以不存在容量不足的问题,因此这里没有扩容的方法。
- 内存:须要更多的内存,LinkedList 每一个节点中须要多存储先后节点的信息,占用空间更多些(previous element next)。
- 元素容许为null。
- Fail-Fast机制:同ArrayList相同。
- 遍历方法:全部指定位置的操做都是从头开始遍历进行的。LinkedList是基于链表实现的,所以插入删除效率高,查找效率低(虽然有一个加速动做)。源码中先将index与长度size的一半比较,若是index<size/2,就只从位置0日后遍历到位置index处,而若是index>size/2,就只从位置size往前遍历到位置index处。这样能够减小一部分没必要要的遍历,从而提升必定的效率(实际上效率仍是很低)。Arrays.copyOf() 方法:
- 它适合删除,插入较多的场景。
3. Vector
1. Vector 结构图

Vector 类能够实现可增加的对象数组。与数组同样,它包含可使用整数索引进行访问的组件。可是,Vector 的大小能够根据须要增大或缩小,以适应建立 Vector 后进行添加或移除项的操做。Vector 是同步的,可用于多线程。多线程
- Vector 继承了AbstractList,实现了List;因此,它是一个队列,支持相关的添加、删除、修改、遍历等功能。
- Vector实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,咱们便可以经过元素的序号快速获取元素对象;这就是快速随机访问。
- Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。
- Vector 实现Serializable接口,支持序列化。
2. Vector 重要特色
- 本质实现:可增加的对象数组。
- 线程安全:同步的,不少方法都加入了synchronized同步语句,来保证线程安全。
- 列表长度:elementCount表示实际元素的数量。(Vector 经过 capacity (容量) 和 capacityIncrement (增加数量) 来尽可能少的占用空间)
- 列表容量:Vector初始化容量是10,扩容默认2倍。capacityIncrement 容量增加系数(向量的大小大于其容量时,容量自动增长的量),ensureCapacity(int minCapacity)调用ensureCapacityHelper(int minCapacity)若是此向量的当前容量小于
minCapacity
,则经过将其内部数据数组(保存在字段 elementData
中)替换为一个较大的数组来增长其容量。新数据数组的大小将为原来的大小加上 capacityIncrement
,若是容量的增量小于等于零,则每次须要增大容量时,向量的容量将增大一倍(编程原来的两倍),不过,若是此大小仍然小于 minCapacity
,则新容量将为 minCapacity
。
- Fail-Fast机制:Vector 的 iterator 和 listIterator 方法所返回的迭代器是快速失败的:若是在迭代器建立后的任意时间从结构上修改了向量(经过迭代器自身的 remove 或 add 方法以外的任何其余方式),则迭代器将抛出 ConcurrentModificationException。所以,面对并发的修改,迭代器很快就彻底失败,而不是冒着在未来不肯定的时间任意发生不肯定行为的风险。
- Vector 的 elements 方法返回的 Enumeration 不是 快速失败的。
- Vector 主要用在事先不知道数组的大小,或者只是须要一个能够改变大小的数组的状况。
- 最好在插入大量元素前增长 vector 容量,那样能够减小从新申请内存的次数。
3. Array vs Vector
共同点:并发
- 都是基于数组
- 都支持随机访问
- 默认容量都是 10
- 都有扩容机制
区别:dom
- Vector 出生的比较早,JDK 1.0 就出生了,ArrayList JDK 1.2 才出来
- Vector 比 ArrayList 多一种迭代器 Enumeration
- Vector 是线程安全的,ArrayList 不是
- Vector 默认扩容 2 倍,ArrayList 是 1.5
若是没有线程安全的需求,通常推荐使用 ArrayList,而不是 Vector,由于每次都要获取锁,效率过低。
4. Stack
1. Stack 结构图

Stack 类表示后进先出(LIFO)的对象堆栈。它经过五个操做对类 Vector 进行了扩展 ,容许将向量视为堆栈。它提供了一般的 push 和 pop 操做,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并肯定到堆栈顶距离的 search 方法。
由于它继承自Vector,那么它的实现原理是以数组实现堆栈的。若是要以链表方式实现堆栈可使用LinkedList!(由于)
2. Stack 重要特色
- Stack是栈。它的特性是:先进后出(FILO, First In Last Out)。
- Stack实际上也是经过数组去实现的。实际调用的实现方法都是Vector中的方法!
- push时(即,将元素推入栈中),是经过将元素追加的数组的末尾中。
- peek时(即,取出栈顶元素,不执行删除),是返回数组末尾的元素。
- pop时(即,取出栈顶元素,并将该元素从栈中删除),是取出数组末尾的元素,而后将该元素从数组中删除。
- 栈最大的长度取决于vector里面数组能有多长。这里vector里面最大能取到Integer.MAX_VALUE。
5.CopyOnWriteArrayList(JUC)
1. CopyOnWriteArrayList 结构图

CopyOnWrite容器即写时复制的容器。通俗的理解是当咱们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,而后新的容器里添加元素,添加完元素以后,再将原容器的引用指向新的容器。这样作的好处是咱们能够对CopyOnWrite容器进行并发的读,而不须要加锁,由于当前容器不会添加任何元素。因此CopyOnWrite容器也是一种读写分离的思想,读和写不一样的容器。添加的时候是须要加锁的.
2. CopyOnWriteArrayList重要特色
- 增删改都须要得到锁,而且锁只有一把,而读操做不须要得到锁,支持并发。(而Vector读也须要加锁,性能差)
- 读的时候不须要加锁,若是读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读仍是会读到旧的数据,由于写的时候不会锁住旧的CopyOnWriteArrayList。
- 应用:CopyOnWrite并发容器用于读多写少的并发场景。好比白名单,黑名单,商品类目的访问和更新场景。
- 缺点:即内存占用问题(写时复制机制->GC->应用响应时间长)和数据一致性问题(只能保证数据的最终一致性,不能保证数据的实时一致性)。
- CopyOnWriteArrayList 是一个线程安全的 ArrayList,经过内部的 volatile 数组和显式锁 ReentrantLock 来实现线程安全。
-
CopyOnWriteArrayList 实现很是简单。内部使用了一个 volatile 数组(array)来存储数据,保证了多线程环境下的可见性。在更新数据时,都会新建一个数组,并将更新后的数据拷贝到新建的数组中,最后再将该数组赋值给 array。正因为这个缘由,涉及到数据更新的操做效率很低。
抄录网址
- https://blog.csdn.net/u010648555/column/info/14681(Java集合系列专栏)
- https://blog.csdn.net/ns_code/article/category/2362915(Java集合源码剖析)
- http://www.cnblogs.com/skywang12345/p/3323085.html( Java 集合系列)
- http://ifeve.com/talk-concurrency/(聊聊并发系列)
- Java List集合深刻学习
- java集合系列——List集合之ArrayList介绍(二)
- 深刻Java集合学习系列:ArrayList的实现原理
- java集合入门和深刻学习,看这篇就差很少了
- ArrayList 源码分析 -- 扩容问题及序列化问题
- 【Java集合源码剖析】ArrayList源码剖析
- ArrayList的elementData为何要用transient修饰
- java ArrayList的序列化分析
- 何巧妙的使用ArrayList的Clone方法
- Java 集合深刻理解(11):LinkedList
- java集合系列——List集合之LinkedList介绍(三)
- 【Java集合源码剖析】LinkedList源码剖析
- LinkedList API
- 聊聊并发-Java中的Copy-On-Write容器