1.ArrayList
ArrayList底层是数组实现的存储,与它类似的是LinkedList,两者间的区别:
- ArrayList:查找与访问元素的速度快,但是新增、删除的速度慢。
- LinkedList:新增、删除的速度快,查找的速度慢。
2.ArrayList为什么是线程不安全的还使用?
- 平时的场景中,基本都是用来查询的,不会设计太频繁的新增和删除
- 如果设计到新增和删除可以使用LinkedList。
- 如果需要线程安全,可以使用Vector。
3.ArrayList底层是如何实现的?
- 在new ArrayList()创建一个集合的时候,会初始化一个容量为0的Object[]
- 当再次执行add添加数据的时候,才会默认分配一个capacity=10的初始容量
4.ArrayList可以存放无限长度的数组是如何实现的?
通过数组扩容方式,如果有一个长度为10的数组,要新增一个元素,发现数组已经满了,它会执行一下几个步骤:
- 重新定义一个长度为10+10/2的数组。
- 然后把原有的数组原封不动的复制到新得数组中,再把指向原数组中的地址换到新数组的地址。
5.ArrayList新增时为什么慢?
- 首先在新增的时候会进行一个长度校验的判断 ensureCapacityInternal,判断是否需要扩容。
- 扩容的时候,jdk8以后采用了位运算符,效率更高。
int newCapacity = oldCapacity + (oldCapacity>>2)
- 如果是新增指定位置的时候,校验后,就直接copy指定位置的元素到最后的元素,把新增的元素插入指定位置的数组后,再把之前copy的数组依次添加到后面。
若当数组较大的时候,新增一个指定位置的数组,后面的元素全部都要复制一边。然后涉及到扩容啥的速度自然而然就变慢了
6.ArrayList创建时指定数组大小是否会初始化数组长度?
不会,数组创建的时候是再add添加元素的时候。
7.ArrayList插入删除一定很慢么?
取决于你删除的元素离数组末端的元素有多远。
8.ArrayList删除是怎么实现的?
比如有一个数组长度为10。要删除index为2的元素。
- 先复制一个从 index+1 开始到最后的数组;即 3->10。
- 把这个新数组从原数组index的位置开始放到最后。
其实就是把原来的index下标的元素给覆盖掉了,给你一种被删除的感觉。
同理它的效率很低,如果数组很大,它需要复制和移动的位置就很大。
9.ArrayList线程安全么?
不安全,安全的数组容器时Vector。Vector的实现很简单:所有的方法加上了synchronized锁。
10.ArrayList适合做队列么?
不适合,队列一般时先进先出,如果使用ArrayList做队列,就需要再数组尾添加数据,数组头删除数据。无论如何总会有操作设计到数组的数据搬迁,即复制和移动。效率低下所以不适合做队列。
11.数组适合做队列么?
适合,ArrayBlockingQueue内部就是一个环形队列,它是一个定长队列。内部是用一个定长数组来实现的
环形队列:使用两个偏移量来标记数组的读位置和写位置,如果超过长度则折回到数组开头。
12.ArrayList与LinkedList遍历性能比较?
ArrayList比LinkedList快。
- ArrayList的遍历最大的优势在于内存的连续性,cpu内部缓存结构会缓存连续内存片段,大幅度降低了读取内存的性能开销。
- LinkedList是双向链表结构,内存是不连续的,并且如果get每一个元素都会导致之前遍历的元素重新遍历一边