ArrayList、LinkedList和Vector的区别
1.三者之间的关系
- List接口:存储有序的、可重复的数据,—> “动态数据”
- ArrayList:作为List接口的主要实现类,线程不安全的,执行效率高,底层使用Object[]存储
- LinkedList:对于频繁的插入和删除操作,使用此类比ArrayList效率高,底层使用双向链表存储
- Vector:作为List接口的古老实现类,线程安全的,执行效率低,底层使用Object[]存储
2.ArrayList和LinkedList之间的区别
(1)相同点
ArrayList和LinkedList都继承了AbstractList抽象类,都实现了List接口
ArrayList和LinkedList是两个集合类,用于存储对象引用
(2)不同点
ArrayList底层通过动态数组实现,而LinkedList底层通过双向链表实现
ArrayList根据索引查找元素的效率比较高,但是插入、删除数据时性能比较低,需要将待插入或删除元素之后的元素往后或往前移动
LinkedList查询元素的效率比较低,需要从头部或尾部开始查找,挨个遍历每一个元素直到找到所需元素,但是插入、删除元素的效率比较高,比如,删除一个元素只需要把它的前一个元素的指针指向它后一个元素就可以
3.ArrayList和Vector之间的区别
(1)相同点
ArrayList和LinkedList都继承了AbstractList抽象类,都实现了List接口
ArrayList和Vector底层都是通过数组实现的
默认初始化大小都是10
(2)不同点
Vector是线程安全的,而ArrayList是线程不安全的,Vector类中的方法通过synchronized修饰实现线程的同步,但实现同步需要很高的开销,这也导致了访问Vector比ArrayList慢
ArrayList和Vector都是采用连续的内存空间存储元素,但是当空间不足的时候,两个类扩容的方式是不同的。(ArrayList每次存储时会检查空间大小,不够时会扩充为原来的1.5倍,Vector会扩充为原来空间的2倍
ArrayList扩容:
Vector扩容
Vecot可以设置增长因子,而ArrayList不可以
4.源码分析
ArrayList的源码分析:
- jdk7中ArrayList的情况
List list = new ArrayList();//底层创建了长度是10的Object[]数组
List.add(123);//elementData[0] = new Integer(123);
..
List.add(11);//如果此次的添加导致底层elementData的数组容量不够,则扩容
默认情况下,扩容为原来容量的1.5倍,同时需要将原来数组中的数据复制到新的数组中
结论:建议开发中使用带参的构造器,ArrayList list = new ArrayList(capacity);
- jdk8中ArrayList的变化
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{},并没有创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度为10的数组,并将数据123添加到elementData[0]
...
后续的添加和扩容操作与jdk7无异
- 小结:jdk7中的ArrayList的创建类似于单例的饿汉式,而jdk8中的ArrayList对象的创建类似于单例的懒汉式,延迟了数组的创建节省了内存
LinkedList源码分析:
- jdk8中的LinkedList源码分析
LinkedList list = new LinkedList();//内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象,其中,Node定义为:体现了LinkedList双向链表的说法
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Vector的源码分析
- jdk7和jdk8中通过Vector()创建对象时,底层都创建了长度为10的数组,在扩容方面,默认扩容为原来数组长度的2倍