ArrayList与LinkedList
数组和链表的区别
数组:
处理一组数据类型相同的数据。但是不允许动态定义数组的大小,即在使用数组之前必须确定数组的大小。这样数组中的有些空间可能不被使用,从而造成内存空间的浪费。当数据增加时,可能超出原先定义的元素个数,造成数组越界。数组插入删除时需要移动其他数据项。但是查询方便。
数组从栈中分配空间,对于程序员方便快速,数组无需初始化,因为数组元素在内存的栈区,系统自动申请空间。但是自由度小。数组元素在内存中连续
链表:
链表动态的进行存储分配,可以适应数据动态地增减的情况,且可以方便地插入、删除数据项。链表插入和删除时,只需要改变个别元素之间的关系,这大大提高了链表的删除和插入的速度。查询时需要从前往后遍历。
链表从堆中分配空间,自由度大,但是申请管理比较麻烦,链表的结点元素在内存的堆区,每个元素须手动申请空间。链表在内存中不一定连续。
ArrayList
ArrayList是基于动态数组的数据结构。实现了list接口,是以数组的方式实现的。所谓动态数组是这样实现的,如果没有指定数组的大小,则申请默认大小为10 的数组,当元素个数增加,数据无法存储时,系统会另外申请一个长度为当前长度的1.5倍的数组,然后把之前的数据拷贝到新建的数组中。
数组的特征是可以使用索引的方式来快速定位对象的位置。适合读取数据。
以下是
Arraylist部分源码:
Arraylist扩容:
Arraylist添加数据:(向数组尾部添加)
向数组的指定位置添加数组:
可以看到,只要ArrayList的当前容足够大,add()操作向数组的尾部的效率非常高的,当向数组指定位置添加yi据时,会进行大量的数组移动复制操作。而数组复制时,最终将调用System.arraycopy()方法,因此add()操作的效率还是相当高的。尽管这样当向指定位置添加数据时也还是比Linkedlist慢,后者添加数据只需要改变指针指向即可。Arraylist删除数组也需要移动数组,效率较慢。
ArrayList总结
1.底层是object数组存数据
2.扩容机制:默认大小是10,扩容是扩容到之前的1.5倍大小,每次扩容是将原数组中的数据复制到新的数组中
3.添加:如果是添加到数组的指定位置,那么可能会挪动大量的数组元素,并且可能会触发扩容机制;如果是添加到末尾的话,那么只可能触发扩容机制.
4.删除:如果是删除数组指定位置的元素,那么可能会挪动大量的数组元素;如果是删除末尾元素的话,那么代价是最小的. ArrayList里面的删除元素,其实是将该元素置为null.
5.查询和改某个位置的元素是非常快的( O(1) ).
浅复制与深复制概念
浅复制
浅复制实例和原始实例的引用类型引用同一个对象;
深复制
深复制实例和原始实例的引用类型引用不同对象。
LinkedList
LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。有关索引的操作可能从链表头开始遍历到链表尾部,也可能从尾部遍历到链表头部,这取决于看索引更靠近哪一端。
LinkedList 实现 List 接口,能对它进行队列操作。
LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。
LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。
LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。
LinkedList 是非同步的。
LinkedList内部是一个双端链表的结构
关键字transient 序列化对象的时候,这个属性就不会序列化到指定的目的地中
ArrayList与LinkedList使用场景
对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。
对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。