文章目录
参考文章:《求求大厂给个Offer》 List面试题(java3y)
List(jdk1.8)
1.了解List吗?你对List了解多少?
- List在Java里边是一个接口,常见的实现类有ArrayList和LinkedList,在开发中用得最多的是ArrayList
2.ArrayList和LinkedList的区别?
- 二者都是list接口下的实现类,都是有序、可排序、可重复的集合,都支持迭代器操作,二者都是非线程安全的
- ArrayList的底层数据结构是数组,访问速度快,LinkedList底层数据结构是链表,增删速度快
- ArrayList没有实现Queue接口、Deque接口,不支持队列操作,LinkedList实现了Queue接口和Deque接口,支持队列操作,同时支持栈操作
- ArrayList内部采用倍数增长的方式扩容(1.5)
- LinkedList内部采用链表实现,不需要扩容
3.我们本身就有数组了,为什么还要用ArrayList呢?
- 原生的数组有一个特点,你在使用的时候必须为它创建一个大小,并且创建了之后不能更改,而ArrayList不需要指定,而且它可以实现动态增长,可以应用到更多的场合
4.ArrayList怎么实现的?为什么ArrayList不需要创建大小?
- 当我们new时,默认会有一个空的Object数组,大小为0,当我们第一次add添加数据的时候,会给这个数组初始化一个大小,这个大小默认值为10
- 使用ArrayLIst在每一次add的时候,他都会先去计算这个数组够不够空间,如果空间是足够的,那么直接加上去就好了,如果不够就需要扩容,一次扩大原来的1.5倍
- 在源码中,有个grow方法,每一次扩原来的1.5倍,空间扩容完了之后,会调用arraycopy来对数组进行拷贝
5.为什么在开发中用到最多的是ArrayList?
- 是由底层的数据结构来决定的,在日常开发中,遍历的需求比增删要多,即便是增删也是往往在list的尾部添加就ok了,像在尾部添加元素,ArrayList的时间复杂度也就O(1)
- 另外,ArrayList的增删底层调用的copyOf()被优化过,现代cpu对内存可以进行块操作,ArrayList的增删一点也不会被LinkedList慢(不过Leetcode上本人亲测,LinkedList增删确实比ArrayList快一些,很短的时间,针对算法)
6.线程安全的List还有什么?
- 首先我们可以用Collections来将ArrayList来包装一下,变成线程安全,不过这个一般使用不多,一般使用较多的是在java.util.concurrent包下还有一个类,叫做CopyOnWriteArrayList
- 它的底层是通过复制数组的方式来实现的
- 它的add方法的实现
- 在add方法时其实它会加lock锁,然后会复制出一个新的数组,往新的数组里边add真正的元素,最后把array的指向改变为新的数组。其实get方法又或是size方法只是获取array所指向的数组的元素或者大小,读不加锁,写加锁
7.CopyOnWriteArrayList有什么缺点?
- 很耗费内存,每次set()/ add() 都会复制一个数组出来,另外就是CopyOnWriteArrayList只能保证数据的最终一致性,不能保证数据的实时一致性。假设两个线程,线程A去读取CopyOnWriteArrayList的数据,还没有读完,现在线程B将这个List清空了,但是线程A此时还是可以把剩余的数据给读出来。