您的位置: 首页 > 编程笔记

Java基础篇(四):ArrayList和LinkedList内部实现、区别、使用场景

Java ArrayList LinkedList 时间:2019-08-19  查看:13   收藏

ArrayList和LinkedList都是实现了List接口的类,他们都是元素的容器,用于存放对象的引用;

他们都可以对存放的元素进行增删改查的操作,还可以进行排序。

但是,他们还是有区别的。

除了实现对List接口的实现,他们还实现了其他的接口,由此造就了他们之间的差异;


ArrayList:内部使用数组的形式实现了存储,实现了RandomAccess接口,利用数组的下面进行元素的访问,因此对元素的随机访问速度非常快。

因为是数组,所以ArrayList在初始化的时候,有初始大小10,插入新元素的时候,会判断是否需要扩容,扩容的步长是0.5倍原容量,扩容方式是利用数组的复制,因此有一定的开销;

另外,ArrayList在进行元素插入的时候,需要移动插入位置之后的所有元素,位置越靠前,需要位移的元素越多,开销越大,相反,插入位置越靠后的话,开销就越小了,如果在最后面进行插入,那就不需要进行位移;

LinkedList:内部使用双向链表的结构实现存储,LinkedList有一个内部类作为存放元素的单元,里面有三个属性,用来存放元素本身以及前后2个单元的引用,另外LinkedList内部还有一个header属性,用来标识起始位置,LinkedList的第一个单元和最后一个单元都会指向header,因此形成了一个双向的链表结构。

LinkedList的元素并不需要连续存放,但是每个存放元素的单元比元素本身需要更大的空间,因为LinkedList对空间的要求比较大,但是扩容的时候不需要进行数组复制,因此没有这一环节的开销。

但是,是的,就是但是,也正因为这样,LinkedList的随机访问速度惨不忍睹,因为无论你要访问哪一个元素,都需要从header起步正向或反向(根据元素的位置进行的优化)的进行元素遍历;

由此可见,ArrayList适合需要大量进行随机访问的场景;而LinkedList则适合需要在集合首尾进行增删的场景。

以上都是随手度娘就能查到的信息。


其实ArrayList也有适合做增删的场景——那就是越靠近尾部的元素进行增删时,其实效率比LinkedList要高


我当然不是第一个发现的,网上也有很多人写过测试的demo,我也自己写过,同时往ArrayList和LinkedList塞入上万个元素,然后在指定位置连续插入元素(循环次数越大越明显)。

指定位置从头部开始逐步后移,可以明显的看到,ArrayList消耗的时间越来越短成线形越来越短(符合前面提到的,插入位置越靠后,开销越小);

而LinkedList则是成正态分布,当位置处于集合中部的时候,最慢。究其原因,因为LinkedList插入元素是需要先进行元素的查找定位,然后才能进行首尾链接的拆分、重新指向新元素的,然而LinkedList的遍历有多低效,大家也是清楚明白的。

真实的业务场景中,一般都是随机访问和增删并存的,因为ArrayList的出场率显然比LinkedList要高,比较常用;当然,如果出现了需要类似队列结构的先进先出这种需要在首尾都进行增删操作,或是栈结构在头部操作元素的情况,自然是要选择LinkedList了,毕竟LinkedList是实现了队列接口的。

附上测试截图:
100万个元素,循环插入1000次;


位置靠前.png

数组超越链表.png

中间位置.png

接近尾部.png

四张截图可以看出,ArrayList消耗时间的线性减少,而LinkedList则是正态分布。


好了,稍微啃了一下关于ArrayList和LinkedList的实现源码,对其的认识也在度娘上的各种技术文之上有了一定的加深,这里算是一个小小的总结。

下一篇——内存溢出是怎么回事

 

0% (0)
0% (0)