1、底层数据结构的差异:
ArrayList:数组,连续的一块内存空间,基于动态数组;
LinkedList:双向链表,不是连续的内存空间,基于链表的数据结构,每一个元素都是与前一个和后一个元素相连的。(由链表的特性决定);
2、性能区别:
ArrayList:查询快,因为是连续的内存空间,方便寻址,但是删除,插入效率慢,因为需要发生数据迁移;
LinkedList:查询慢,因为需要通过指针一个个寻址,但是删除和插入快,因为只要改变前后节点的指针即可;
3、添加、删除、修改分析
(1)ArrayList:
(a)添加,添加到末尾,正常不需要做什么特别的处理,除非现有的数组空间不够,需要扩容;
(b)添加到其他位置(可以理解为插入),这个时候就需要做数据的整体迁移,效率不高;
(c)修改,修改之前必须先定位,因为ArrayList是数组(一段连续的内存空间),因此它的查询,定位效率很高;
(d)删除,删除末尾,不需要数据的迁移;但是删除其他位置,这时候就需要数据的迁移;
(2)LinkedList:
(a)添加,第一种情况是添加到末尾,创建一个新的节点,将之前的last节点设置为新节点的pre,新节点设置为last;第二种情况是添加到其他位置,这个时候只需要调整前后节点的引用指向;
ArrayList分析:
jdk 7 情况下:
ArrayList list = new ArrayList();//底层创建了长度是10的Object[]数组elementData; list.add(123);//elementData[0] = new Integer(123);
list.add(11);//如果此次的添加导致底层elementData数组容量不够,则扩容。默认情况下,扩容为原来的容量的1.5倍(使用位运算符右移一位),同时需要将原有数组中的数据复制到新的数组中。
结论:建议开发中使用带参的构造器:ArrayList list = new ArrayList(int capacity)
jdk 8 中ArrayList的变化:
ArrayList list = new ArrayList();//底层Object[] elementData初始化为{}.并没有创建长度为10的数组
list.add(123);//第一次调用add()时,底层才创建了长度10的数组,并将数据123添加到elementData[0]
后续的添加和扩容操作与 jdk 7 无异。
小结:jdk7中的ArrayList的对象的创建类似于单例的饿汉式,而jdk8中的ArrayList的对象的创建类似于单例的懒汉式,延迟了数组的创建,节省内存。
LinkedList分析:
LinkedList list = new LinkedList(); //内部声明了Node类型的first和last属性,默认值为null
list.add(123);//将123封装到Node中,创建了Node对象。
其中,Node定义为:
private static class Node {
E item;
Node next;
Node prev;
Node(Node prev, E element, Node next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
体现了LinkedList的双向链表的说法