List集合中 ArrayList和LinkList底层实现原理

 1.ArrayList

    ArrayList底层是由动态数组实现的。动态数组就是长度不固定,随着数据的增多而变长。当实例化ArrayList时(比如:List<Integer> intList = new ArrayList<>();),如果不指定它的长度,则默认为10,如下图:

List集合中 ArrayList和LinkList底层实现原理

当ArrayList增加元素时,它是按照顺序从头部开始往后添加,它是有顺序的。如下图

List集合中 ArrayList和LinkList底层实现原理

如果当添加的元素超过当前数组的长度时,它会新创建一个数组,长度为当前数组的1.5倍,然后将当前数组的元素复制到新的数组,当前数组的内存被释放。如下图

List集合中 ArrayList和LinkList底层实现原理

根据上图我们可以发现新的数组由原来的长度10变为现在的15.

    我们知道,数组是用来存储固定大小的同类型元素,数组存放位置是在jvm的堆中。当有新的元素需要存储时,都会存储在最前面,因此每次存储,所有的元素都会向后移动位置。同理,如果删除一个元素,后面的元素都会向前移动一个位置。因此,ArrayList在存储和删除的时候效率比较低。

    但是由于每个元素占用的内存相同且是连续排列的,因此在查找的时候,根据元素的下标可以迅速访问数组中的任意元素,查询效率非常高。

2:LinkedList

    LinkedList底层是由双向链表的数据结构实现的。

List集合中 ArrayList和LinkList底层实现原理

由上图可以看到:双向链表是由三个部分组成:prev、data、next.

prev:由用来存储上一个节点的地址;

data:是用来存储要存储的数据;

next:是用来存储下一个节点的地址。

List集合中 ArrayList和LinkList底层实现原理

上图可以看出双向链表每个元素之间的联系。我故意将每个链表画的分布不均匀是因为它不像数组一样是连续排列的,双向链表是可以占用一段不连续的内存空间。

当我们有新元素插入时,只需要修改所要插入位置的前一个元素的next值和后一个元素的prev值即可。比如我们在数据2与数据6之间插入一个数据4的元素,那么只需要修改数据2的next值和数据6的prev值。如下图

List集合中 ArrayList和LinkList底层实现原理

删除也是同理,比如要删除数据8的元素,只需要修改数据7的next值和数据9的prev值即可,然后数据8没有元素指向它,它就成了垃圾对象,最后被回收。因此在增加和删除的时候只需要更改前后元素的next和prev值,效率非常高。但是在查询的时候需要从第一个元素开始查找,直到找到我们需要的数据为止,因此查询的效率比较低。