List 源码面试题总结

List 源码面试题总结

List 作为工作中最常见的集合类型,在面试过程中,也是经常会被问到各种各样的面试题,一般来说,只要你看过源码,心中对 List 的总体结构和细节有所了解的话,基本问题都不大。

1、面试题

1.1、 说说你对 ArrayList 的理解?

很多面试官喜欢这种问法,主要是考察面试同学对 ArrayList 有没有总结经验,介于 ArrayList 内容很多,建议先回答总体架构,再从某个细节出发作为突破口,比如这样:
ArrayList 底层数据结构是个数组,其 API 都做了一层对数组底层访问的封装,比如说 add 方法的过程是……(这里可以引用我们在ArrayList 源码解析和设计 中 add 的过程)。

一般面试官看你回答得井井有条,并且没啥漏洞的话,基本就不会深究了,这样面试的主动权就掌握在自己手里面了,如果你回答得支支吾吾,那么面试官可能就会开启自己面试的套路了。

1.2 、扩容类问题

1.2.1、ArrayList 无参数构造器构造,现在 add 一个值进去,此时数组中元素个数是多少,下一次扩容前最大可用大小是多少?

由于是无参构造函数,add一个值进去的时候会触发扩容操作,ArrayList第一次扩容时是有默认值的,默认值是10,所以在第一次 add 一个值进去时,数组的元素个数(size)是1,数组大小(capacity)就变成10了。

1.2.2、如果我连续往 list 里面新增值,增加到第 11 个的时候,数组的大小是多少?

此时我们希望数组的大小为 11,但实际上数组的最大容量只有 10,不够了就需要扩容,扩容的公式是:oldCapacity + (oldCapacity>> 1),oldCapacity 表示数组现有大小,目前场景计算公式是:10 + 10 /2 = 15,然后我们发现 15 已经够用了,所以数组的大小会被扩容到 15。

1.2.3、数组初始化,被加入一个值后,如果我使用 addAll 方法,一下子加入 15 个值,那么最终数组的大小是多少?

上面我们已经知道加入一个值后,数组的可用大小是10,现在需要一下子加入15个值,显然会触发扩容操作,扩容之后数组容量变成15,还是不够,这时候源码有一种策略,如果扩容后的值 < 我们的期望值,我们的期望值就等于本次扩容的大小。

// newCapacity 本次扩容的大小,minCapacity 我们期望的数组最小大小
// 如果扩容后的值 < 我们的期望值,我们的期望值就等于本次扩容的大小
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

所以最终数组扩容后的大小为 16。

1.3 、删除类问题

以下这段代码的执行完成后,List里面剩下的元素是什么?

List<String> list = new ArrayList<String>() {
    
    {
    
    
  add("2");
  add("3");
  add("3");
  add("3");
  add("4");
}};
for (int i = 0; i < list.size(); i++) {
    
    
  if (list.get(i).equals("3")) {
    
    
    list.remove(i);
  }
}

答案是{2,3,4},最后一个元素3会删除不掉的,因为利用remove()方法,每次删除一个元素3,数组的元素都会减1,所以要删除最后一个3的时候,程序会退出for循环。

1.4、对比类问题

1.4.1、 ArrayList 和 LinkedList 应用场景有何不同?

ArrayList 更适合于快速的查找匹配,不适合频繁新增删除,像工作中经常会对元素进行匹配查询的场景比较合适,LinkedList 更适合于经常新增和删除,对查询反而很少的场景。

1.4.2、 ArrayList 和 LinkedList 两者有没有最大容量?

ArrayList 有最大容量的,为 Integer 的最大值,大于这个值 JVM 是不会为数组分配内存空间的,LinkedList 底层是双向链表,理论上可以无限大。但源码中,LinkedList 实际大小用的是 int 类型,这也说明了 LinkedList 不能超过 Integer 的最大值,不然会溢出。

1.4.3、ArrayList 和 LinedList 是线程安全的么,为什么?

首先,两者都不是线程安全的。两者作为非共享变量时,比如说仅仅是在方法里面的局部变量时,是没有线程安全问题的,只有当两者是共享变量时,才会有线程安全问题。主要的问题点在于多线程环境下,所有线程任何时刻都可对数组和链表进行操作,这会导致值被覆盖,甚至混乱的情况。

2、总结

List 在工作中经常遇到,熟读源码不仅仅是为了应对面试,也为了在工作中使用起来得心应手,如果想更深入了解 List,可以看一遍 ArrayList 源码之后,自己重新实现一个 List。这样的话,就会对 List 底层的数据结构和操作细节理解更深。

猜你喜欢

转载自blog.csdn.net/weixin_38478780/article/details/107729921