Vector、ArrayList、LinkedList的区别
这三者都是实现集合框架中的List,也就是所谓的有序集合。
Vector是Java早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择,毕竟同步是有额外开销的。Vector内部是使用对象数组来保存数据,可以根据需要自动的增加容量,当数组已满时,会创建新的数组,并拷贝原有数组数据。
ArrayList是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与Vector近似, ArrayList也是可以根据需要调整容量,不过两者的调整逻辑有所区别,Vector在扩容时会提高1倍,而ArrayList则是增加50%。
LinkedList顾名思义是Java提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。
ArrayList | Vector | LinkedList | |
---|---|---|---|
底层实现方式 | Object数组 | Vector是基于synchronized实现的线程安全的ArrayList. Vector在扩容时会提高一倍,而ArrayList则是增加50% | 双向循环链表(JDK1.6之前) 双向链表(JDK1.7取消了循环) |
读写机制 | 插入:超过当前数组预定义的最大值时,数组需要扩容,扩容过程需要调用底层System.arraycopy()方法进行数组复制操作 删:删除元素时并不会减少数组的容量,如需缩小容量,可调用trimToSize()方法,在查找元素时要遍历数组,对非null的元素采取equals的方式查找 | 插入:须创建一个新的Entry对象,并更新相应元素的前后元素的引用 在查找元素时,需遍历链表 在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除 | |
读写效率 | ArrayList对元素的增加和删除都会引起数组的内存分配空间动态发生变化,对其进行插入和删除速度较慢,但检索速度快 | LinkedList由于基于链表方式存放数据,增加和删除元素的速度较快,但检索速度较慢 | |
线程安全性 | 非线程安全 | 非线程安全 |
不同容器类型适合的应用场景
- Vector和ArrayList作为动态数组,其内部元素以数组形式顺序存储的,所以非常适合随机访问的场合。除了尾部插入和删除元素,往往性能会相对较差,比如我们在中间位置插入一个元素,需要移动后续所有元素。
- LinkedList进行节点插入、 删除却要高效得多,但是随机访问性能则要比动态数组慢
- 在应用开发中,如果事先可以估计到,应用操作是偏向于插入、删除,还是随机访问较多,就可以针对性的进行选择
数组和链表的对比
- 数组
- 最好用于索引有语意的情况,例如
scores[2]
- 最大的优点:支持快速查询(随机访问)
- 物理存储单元上连续
- 最好用于索引有语意的情况,例如
- 链表
- 不适合用于索引有语意的情况
- 优点:动态数据结构,不需要处理固定容量的问题
- 缺点:丧失了随机访问能力
- 物理存储单元上不连续
ArrayList部分源码分析
add(E e)
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
// 自动扩容机制的核心
ensureCapacityInternal(size + 1); // Increments modCount!!
// 将元素添加到末尾
elementData[size++] = e;
return true;
}
扩容
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 扩容为原来的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果扩容1.5倍后还不满足需求,直接扩容为需求值
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}