1. List集合的概念和特点
1.1 概念
1. 有序集合(有序指的是存储顺序)。
2.用户可以控制列表中每个元素的插入位置,可以通过整数索引来访问元素并搜索列表中的元素。
3.与Set集合不同,列表可以存储重复的元素。
1.2 特点
1.存取有序
2.可以重复
3.有索引
2. List集合特有的方法
方法名 | 用途 |
---|---|
void add(int index,E element) | 在集合中指定的位置插入指定的元素。 |
E remove(int index) | 删除指定索引处的元素并返回被删除的元素。 |
E set(int index,E element) | 修改指定索引处的元素并返回被修改的元素。 |
E get(int index) | 返回指定索引处的元素。 |
3. List集合子类的特点
3.1 ArrayList集合
底层是数组结构实现,查询快,增删慢。
3.2 LinkedList集合
底层是链表结构实现,查询慢,增删快。
4. 面试题
关于构造函数
JDK 7以无参构造方法创建ArrayList时,直接创建长度是10的Object[]数组elementData.
JDK 8以无参构造创建ArrayList时,实际上初始化赋值的是一个空数组。当真正对数组进行添加操作时,才开始分配容量。所以向数组添加第一个元素时,数组容量扩容为10.
//判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
if (minCapacity - elementData.length > 0)
//调用grow方法进行扩容,调用此方法代表已经开始扩容了
grow(minCapacity);
}
4.1 ArrayList无参数构造器构造,add一个值进去,此时的数组大小是多少,下一次扩容前最大可用大小是多少?
答:此时的数组大小是1,下一次最大可用大小是10,当add第一个值进去时,数组可用大小被扩容到10.
4.2 如果连续往 list 里面新增值,增加到第 11 个的时候,数组的大小是多少?
根据ArrayList的源码
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// oldCapacity为旧容量,newCapacity为新容量,将新容量更新为旧容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
可知当增加到11时,此时数组容量是10,不够要扩容,根据源码int newCapacity = oldCapacity + (oldCapacity >> 1);10+10/2=15,所以数组大小被扩充到15。
4.3 数组初始化,被加入一个值后,如果使用 addAll 方法,一下子加入 15 个值,那么最终数组的大小是多少?
答:当数组添加一个值后,实际大小是1,最大可用大小是10,现在加入15个值,期望数组大小为16,此时数组大小为10,根据扩容公式(见上)扩容后大小为15,扩容后大小<期望大小,根据源码
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
如果扩容后的值<期望值,扩容后的大小就等于期望值。
4.4 现在有一个很大的数组需要拷贝,原数组大小是 5k,请问如何快速拷贝?
答:数组较大,如果新建数组时,不指定数组大小,会导致频繁扩容,造成拷贝效率低下,
所以在新建数组时,指定新数组大小为5K即可。
4.5 ArrayList和LinkedList对比
4.5.1 ArrayList 和 LinkedList 有何不同?
从底层数据结构来看ArrayList底层是数组,LinkedList底层是双向链表。ArrayList新增时,会先计算再决定是否扩容,把新增的值直接赋值到数组上,LinkedList只需要改变插入节点和其前后节点所指向位置即可。
4.5.2 ArrayList 和 LinkedList 两者有没有最大容量?
答:ArrayList有最大容量,最大容量为Integer的最大值,超过这个值,JVM不会为数组分配内存空间的,LinkedList底层是双向链表,理论上是无限大的,但源码中,LinkedList使用的是int类型,这也说明LinkedList最大容量不能超过Integer的最大值,不然会溢出。
4.5.3 ArrayList 和 LinkedList 是如何对 null 值进行处理的
ArrayList允许null新增、删除。从头开始找到第一个null值删除;LinkedList对null值没有特殊校验,允许新增和删除。
5. 总结
面试时面试官喜欢问集合底层源码的知识,建议多看多分析。