下图是Collection的类继承图
从图中可以看出:Vector、ArrayList、LinkedList这三者都实现了List 接口.所有使用方式也很相似,主要区别在于实现方式的不同,所以对不同的操作具有不同的效率。
- ArrayList 就是动态数组,是Array的复杂版本,动态的增加和减少元素.当更多的元素加入到ArrayList中时,其大小将会动态地增长。它的元素可以通过get/set方法直接访问,因为ArrayList本质上是一个数组。
- Vector 和ArrayList类似, 区别在于Vector是同步类(synchronized).因此,开销就比ArrayList要大。
- LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList.当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比。它还实现了 Queue 接口,该接口比List提供了更多的方法,包括 offer(),peek(),poll()等.
Arraylist 与 LinkedList 异同
- 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
- 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;
- 插入和删除是否受元素位置的影响: ①ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。
- 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
- 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
ArrayList 与 Vector 异同
同步:Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。和ArrayList类似,但属于强同步类。如果你的程序本身是线程安全的(thread-safe,没有在多个线程之间共享同一个集合/对象),那么使用ArrayList是更好的选择。
扩容机制:默认的初始容量都是10,Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.
为什么现在都不提倡使用 Vector 了?
答:因为 Vector 实现并发安全的原理是在每个操作方法上加锁,这些锁并不是必须要的,在实际开发中一般都是通过锁一系列的操作来实现线程安全,也就是说将需要同步的资源放一起加锁来保证线程安全,如果多个 Thread 并发执行一个已经加锁的方法,但是在该方法中又有 Vector 的存在,Vector 本身实现中已经加锁了,双重锁会造成额外的开销,即 Vector 同 ArrayList 一样有 fail-fast 问题(即无法保证遍历安全),所以在遍历 Vector 操作时又得额外加锁保证安全,还不如直接用 ArrayList 加锁性能好,所以在 JDK 1.5 之后推荐使用 java.util.concurrent 包下的并发类。此外 Vector 是一个从 JDK1.0 就有的古老集合,那时候 Java 还没有提供系统的集合框架,所以在 Vector 里提供了一些方法名很长的方法(如 addElement(Object obj),实际上这个方法和 add(Object obj) 没什么区别),从 JDK1.2 以后 Java 提供了集合框架,然后就将 Vector 改为实现 List 接口,从而导致 Vector 里有一些重复的方法。
fail-fast 机制是 java 集合 (Collection) 中的一种错误机制。当多个线程对同一个集合的内容进行操作时,就可能会产生 fail-fast 事件。例如:当某一个线程 A 通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变了;那么线程A访问集合时,就会抛出ConcurrentModificationException 异常,产生 fail-fast 事件。