对比Vector、 ArrayList、 LinkedList有何区别?
这三者都是实现集合框架中的List
Vector是Java早期提供的线程安全的动态数组,如果不需要线程安全,并不建议选择。
ArrayList是应用更加广泛的动态数组实现,它本身不是线程安全的,所以性能要好很多。与Vector近似, ArrayList也是可以根据需要调整容量,不过两者的调整逻辑有所区别, Vector在扩容时会提高1倍,而ArrayList则是增加50%。
LinkedList是Java提供的双向链表,所以它不需要像上面两种那样调整容量,它也不是线程安全的。
Vector、 ArrayList、 LinkedList实现方式与应用场景中差别
1 底层实现方式
ArrayList内部用数组来实现; LinkedList内部采用双向链表实现; Vector内部用数组实现。
2 读写机制
ArrayList
插入元素
超过当前数组预定义的最大值时,数组需要扩容,扩容过程需要调用底层System.arraycopy()方法进行大量的数组复制操作;
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
在删除元素时并不会减少数组的容量
(如果需要缩小数组容量,可以调用trimToSize()方法);
/**
* Trims the capacity of this <tt>ArrayList</tt> instance to be the
* list's current size. An application can use this operation to minimize
* the storage of an <tt>ArrayList</tt> instance.
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
在查找元素时要遍历数组,对于非null的元素采取equals的方式寻找。
LinkedList
继承双端队列(Deque)
JDK1.8源码分析之LinkedList
在插入元素时,须创建一个新的Entry对象,并更新相应元素的前后元素的引用;
在查找元素时,需遍历链表;
在删除元素时,要遍历链表,找到要删除的元素,然后从链表上将此元素删除即可。
Vector与ArrayList仅在插入元素时容量扩充机制不一致。对于Vector,默认创建一个大小为10的Object数组,并将capacityIncrement设置为0;当插入元素数组大小不够时,如果capacityIncrement大于0,则将Object数组的大小扩大为现有size+capacityIncrement;如果capacityIncrement<=0,则将Object数组的大小扩大为现有大小的2倍。
3 读写效率
- ArrayList基于数组实现。数组的特点就是连续内存存储,数组下标随机访问时间复杂度为O(1)。
- LinkedList基于双向链表实现。链表的特点是可以存储分散在内存中。
ArrayList添加元素,在没有扩容的情况下尾部插入并且制定初始容量,ArrayList的效率要高于LinkedList!!!
原因:虽然LinkedList不用循环查找元素,但是Linked在添加元素的时候多了new对象的操作。
4 线程安全性
ArrayList、 LinkedList为非线程安全; Vector是基于synchronized实现的线程安全的ArrayList。
需要注意的是:单线程应尽量使用ArrayList, Vector因为同步会有性能损耗;即使在多线程环境下,我们可以利用Collections这个类中为我们提供的synchronizedList(List list)方法返回一个
线程安全的同步列表对象。
5 关于LinkedList迭代遍历
LinkedList在迭代遍历的时候,不要使用fori循环遍历!!!
for循环遍历get (i)的时候,会根据i的值,算出是在这个链表的前一半还是后一半,前一半正序遍历,后一半倒序遍历。
那么例如在get(2)的时候,先找到0位置的node,再去找到下一位的Node 1.再去找到下一位的node 2。会查找3次。而 arrayList只会查找一次。
To Java程序员:切勿用普通for循环遍历LinkedList
参考:
极客时间:《Java核心技术面试精讲》
本笔记根据专栏主题进行学习笔记,虽然参考了许多做了笔记,但是加上了自己的整理,跟原作者的行文可能有很大偏差。如果想查看原版请自行搜索。谢谢