Collection的简化继承结构如下:
这一篇详细介绍List及其主要的实现类。
List
public interface List<E>
extends Collection<E>
有序的 collection。此接口可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
特点:
- 允许重复的元素。
- 元素排列有序。可以通过索引来访问元素,遍历元素。
方法概要:
ArrayList
public class ArrayList<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
List 接口的大小可变数组的实现。
特点:
- 基于数组实现。
- 读写快,增删慢。size、isEmpty、get、set、iterator 和 listIterator 操作都以固定时间运行。add、remove 操作 O(n) 。其他所有操作大体上都以线性时间运行。
- 容量(存储列表元素的数组的大小)随着向 ArrayList 中不断添加元素,而自动增长,增长规则为 数组当前足够的最小容量 * 1.5。可主动提前使用使用 ensureCapacity 操作来增加容量。
- 不是同步的。
详细源码分析。
构造方法:
Vector
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, Serializable
Vector 类可以实现可增长的对象数组。与数组一样,它包含可以使用整数索引进行访问的组件。但是,Vector 的大小可以根据需要增大或缩小,以适应创建 Vector 后进行添加或移除项的操作。
特点:
- 通过数组保存数据。使用默认构造函数时默认容量大小是10。
- 读写快,增删慢。
- 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则(增加系数默认等于0,不得小于0),将容量大小增加一倍。
- 支持线程的同步。很多方法都是synchronized的,因此代价也较高。
构造方法:
LinkedList
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, Serializable
List 接口的链接列表实现。实现所有可选的列表操作,并且允许所有元素(包括 null)。除了实现 List 接口外,LinkedList 类还为在列表的开头及结尾 get、remove 和 insert 元素提供了统一的命名方法。这些操作允许将链接列表用作堆栈、队列或双端队列。
此类实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作。
特点:
构造方法:
方法摘要:
特点:
- 通过双向链表实现。(JDK1.7之前是环形链表,而到了JDK1.7以后优化成了直线型链表结构)
- 随机读取效率低,插入、删除操作效率比较高(效率高是相对的,因为它省去了ArrayList插入数据可能的数组扩容和数据元素移动时所造成的开销,但还是需要定位到要插入的位置)。
- 实现 Deque 接口,为 add、poll 提供先进先出队列操作,以及其他堆栈和双端队列操作(如push、pop、peek等)。
Stack
public class Stack<E>
extends Vector<E>
Stack 类表示后进先出(LIFO)的对象堆栈。它通过五个操作对类 Vector 进行了扩展 ,允许将向量视为堆栈。它提供了通常的 push 和 pop 操作,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并确定到堆栈顶距离的 search 方法。
但更建议使用Deque的实现类来实现栈,如: Deque<Integer> stack = new ArrayDeque<Integer>();
ArrayList、LinkedList和Vector的比较
参考:https://www.cnblogs.com/yw-ah/p/5841327.html
总结:
- 如果涉及到堆栈,队列等操作,应该考虑用List,对于需要快速插入,删除元素,应该使用LinkedList,如果需要快速随机访问元素,应该使用ArrayList。
- 如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。
- 要特别注意对哈希表的操作,作为key的对象要正确复写equals和hashCode方法。
- 尽量返回接口而非实际的类型,如返回List而非ArrayList,这样如果以后需要将ArrayList换成LinkedList时,客户端代码不用改变。这就是针对抽象编程。
同步性
Vector是同步的。这个类中的一些方法保证了Vector中的对象是线程安全的。而ArrayList则是异步的,因此ArrayList中的对象并不是线程安全的。因为同步的要求会影响执行的效率,所以如果你不需要线程安全的集合那么使用ArrayList是一个很好的选择,这样可以避免由于同步带来的不必要的性能开销。
数据增长
从内部实现机制来讲ArrayList和Vector都是使用数组(Array)来控制集合中的对象。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。所以如果你要在集合中保存大量的数据那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。