本文基于 JDK 1.8.0_191

1. 源码对比

  • 实现接口类对比
  • 扩容机制对比
  • 线程安全

1.1 实现接口类对比

ArraryList、LinkList和Vector的区别 - 图1

  1. public class ArrayList<E> extends AbstractList<E>
  2. implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  3. public class LinkedList<E>
  4. extends AbstractSequentialList<E>
  5. implements List<E>, Deque<E>, Cloneable, java.io.Serializable
  6. public class Vector<E>
  7. extends AbstractList<E>
  8. implements List<E>, RandomAccess, Cloneable, java.io.Serializable
  • 它们都实现 List 接口,说明具备列表的增加、删除、遍历元素等特性。

  • ArrayList、Vector 额外实现 RandomAccess 接口,说明他们能在常量时间复杂度内快速随机访问元素。

  • LinkedList 额外实现 Queue 接口,具备队列的入队、出队等特性。

1.2 扩容机制对比

ArrayList

  1. private static final int DEFAULT_CAPACITY = 10; // 定义初始大小
  2. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 定义列表存储元素数量最大值
  3. private void grow(int minCapacity) {
  4. // overflow-conscious code
  5. int oldCapacity = elementData.length; // 现有元素数量
  6. int newCapacity = oldCapacity + (oldCapacity >> 1); // 增加后元素的数量 = 1 + 0.5
  7. if (newCapacity - minCapacity < 0) // 增加后的元素数量 < 现有的空间,不扩容
  8. newCapacity = minCapacity;
  9. if (newCapacity - MAX_ARRAY_SIZE > 0)
  10. newCapacity = hugeCapacity(minCapacity); // 增加后的元素数量 > 大于最大值,尝试分配 Integer.MAX_VALUE 个元素,可能会抛出 OutOfMemoryError
  11. // minCapacity is usually close to size, so this is a win:
  12. elementData = Arrays.copyOf(elementData, newCapacity);
  13. }

Vector

  1. public Vector() {
  2. this(10);
  3. }
  4. protected int capacityIncrement; // 扩容数量值,Vector 初始化不指定时默认为 0
  5. private void grow(int minCapacity) {
  6. // overflow-conscious code
  7. int oldCapacity = elementData.length;
  8. int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); // 当扩容数量值小于 0,那么扩容比例为原来的两倍;否则扩容的数量为这个值。
  9. if (newCapacity - minCapacity < 0)
  10. newCapacity = minCapacity;
  11. if (newCapacity - MAX_ARRAY_SIZE > 0)
  12. newCapacity = hugeCapacity(minCapacity);
  13. elementData = Arrays.copyOf(elementData, newCapacity);
  14. }

LinkList

  1. transient int size = 0;
  • 初始大小:ArrayList、Vector 默认为 10,LinkList 不指定默认为 0
  • 扩容比例:ArrayList 以 1.5 倍进行扩容;Vector 不指定扩容比例时默认为 2 倍进行扩容

1.3 线程安全性

ArrayList

  1. protected transient int modCount = 0;
  2. public boolean add(E e) {
  3. ensureCapacityInternal(size + 1); // Increments modCount!!
  4. elementData[size++] = e;
  5. return true;
  6. }

Vector

  1. protected transient int modCount = 0;
  2. public synchronized void addElement(E obj) {
  3. modCount++;
  4. ensureCapacityHelper(elementCount + 1);
  5. elementData[elementCount++] = obj;
  6. }

Vector add() 方法上增加了 synchronized 关键字,使得 Vector 支持多线程环境下的元素增加删除修改操作。

2. 增删改性能对比

根据数据结构中知识:

顺序表查找元素时间复杂度为 O(1),适用于随机查找元素的场景。

链表增减元素时间复杂度为 O(1),适用于增减元素比较多的场景。

  1. public static void main(String[] args) {
  2. ArrayList arrayList = new ArrayList();
  3. LinkedList linkedList = new LinkedList();
  4. Vector vector = new Vector();
  5. long t1, t2;
  6. t1 = System.nanoTime();
  7. for (int i = 0; i < 10000; i++) {
  8. arrayList.add(i);
  9. }
  10. t2 = System.nanoTime();
  11. System.out.println("ArrayList add:" + (t2 - t1));
  12. t1 = System.nanoTime();
  13. for (int i = 0; i < 10000; i++) {
  14. linkedList.add(i);
  15. }
  16. t2 = System.nanoTime();
  17. System.out.println("linkedList add:" + (t2 - t1));
  18. t1 = System.nanoTime();
  19. for (int i = 0; i < 10000; i++) {
  20. vector.add(i);
  21. }
  22. t2 = System.nanoTime();
  23. System.out.println("vector add:" + (t2 - t1));
  24. }
  25. ArrayList add:6810212
  26. linkedList add:3463194
  27. vector add:4442985

添加元素,ArrayList 花费时间比 LinkList 时间长。

  1. public static void main(String[] args) {
  2. ArrayList arrayList = new ArrayList();
  3. LinkedList linkedList = new LinkedList();
  4. Vector vector = new Vector();
  5. long t1, t2;
  6. for (int i = 0; i < 100000; i++) {
  7. arrayList.add(i);
  8. linkedList.add(i);
  9. vector.add(i);
  10. }
  11. t1 = System.nanoTime();
  12. for (int i = 0; i < 10000; i++) {
  13. arrayList.get(i);
  14. }
  15. t2 = System.nanoTime();
  16. System.out.println("ArrayList get:" + (t2 - t1));
  17. t1 = System.nanoTime();
  18. for (int i = 0; i < 10000; i++) {
  19. linkedList.get(i);
  20. }
  21. t2 = System.nanoTime();
  22. System.out.println("linkedList get:" + (t2 - t1));
  23. t1 = System.nanoTime();
  24. for (int i = 0; i < 10000; i++) {
  25. vector.get(i);
  26. }
  27. t2 = System.nanoTime();
  28. System.out.println("vector get:" + (t2 - t1));
  29. }
  30. ArrayList get:72482
  31. linkedList get:107975370
  32. vector get:242634

查找元素上,ArrayList 最快

3. 总结

将 ArrayList、LinkList 和 Vetor 进行了简单对比,总体来说:

  • 在查找元素比较频繁的场合,推荐使用 ArrayList;在修改元素比较频繁的场合,推荐使用 LinkList。
  • Vetor 与 ArrayList 类似,区别在于扩容比例、线程安全方面。
  • 性能对比测试结果可能存在添加元素 ArrayList 花费时间比 LinkList 多的情况, 这个原因

参考:

ArrayList vs LinkedList vs Vector 区别