前言
只有光头能力变强。
文本已收录至我的 GitHub 精选文章,欢送 Star:https://github.com/ZhongFuCheng3y/3y
从明天开始,我,三歪,正式开始写面试系列。我给这个面试系列取了一个名字,叫做《求求大厂给个 Offer》
上一篇就叫做《求求大厂给个 Offer:如何写简历》
所以这篇文章叫做《求求大厂给个 Offer:List 面试题》
接下来就开始吧。
本文有配套的 视频 观看:https://www.bilibili.com/video/BV1nT4y1L71r/ 欢送 三连。
面试现场
面试官:“你简略自我介绍一下吧”
三歪:“我叫三歪,目前保护一个公众号叫做 Java3y,这几年写了 300+ 原创技术文章,近 1000 页的 原创 电子书和多个知识点的思维导图。我的愿景是:只有关注我并三连的同学都能够拿到大厂 offer。我的 ….”
面试官:“停停停,别吹了,咱们正式开始吧。”
面试官:“来讲讲 Java 的 List 吧,你对 List 理解多少?”
三歪:“List 在 Java 里边是一个接口,常见的实现类有 ArrayList 和 LinkedList,在开发中用得最多的是 ArrayList”
面试官:“你再别离来讲讲 ArrayList 和 LinkedList 的区别呗”
三歪:“ArrayList 的底层数据结构是数组,LinkedList 底层数据结构是链表。”
面试官:“那咱们自身就有数组了,为什么要用 ArrayList 呢?”
三歪:“原生的数组会有一个特点:你在应用的时候必须要为它创立大小,而 ArrayList 不必”
面试官:“那你说说 ArrayList 是怎么实现的吧,为什么 ArrayList 就不必创立大小呢?”
三歪:“其实是这样的,我看过源码 。当咱们new ArrayList()
的时候,默认会有一个空的 Object
数组,大小为 0。当咱们 第一次 add
增加数据的时候,会给这个数组初始化一个大小,这个大小默认值为 10”
面试官:“嗯”
三歪:“还有就是,数组的大小是固定的,而 ArrayList 的大小是可变的”
面试官:“那怎么了解固定和可变的呢?你说说看”
三歪:“假如咱们给定数组的大小是 10,要往这个数组里边填充元素,咱们只能增加 10 个元素。而 ArrayList 不一样,ArrayList 咱们在应用的时候能够往里边增加 20 个,30 个,甚至更多的元素”
三歪:“因为 ArrayList 是实现了动静扩容的”
面试官:“那它是怎么实现的呢?”
三歪:“应用 ArrayList 在每一次 add
的时候,它都会先去计算这个数组够不够空间,如果空间是够的,那间接追加下来就好了。如果不够,那就得扩容”
面试官:“那怎么扩容?一次扩多少?”
三歪:“在源码里边,有个 grow
办法,每一次扩原来的 1.5
倍。比如说,初始化的值是 10 嘛。当初我第 11 个元素要进来了,发现这个数组的空间不够了,所以会扩到 15”
三歪:“空间扩完容之后,会调用 arraycopy
来对数组进行拷贝”
面试官:“哦,能够的。那为什么你在后面提到,在日常开发中用得最多的是 ArrayList 呢?”
三歪:“是由底层的数据结构来决定的,在日常开发中,遍历的需要比增删要多,即使是增删也是往往在 List 的尾部增加就 OK 了。像在尾部增加元素,ArrayList 的工夫复杂度也就O(1)
”
三歪:“另外的是,ArrayList 的增删底层调用的 copyOf()
被优化过,古代 CPU 对内存能够 块操作,ArrayList 的增删一点儿也不会比 LinkedList 慢”
面试官:“Vector 你理解吗?”
三歪:“嗯,Vector 是底层构造是数组,个别当初咱们曾经很少用了。绝对于 ArrayList,它是线程平安的,在扩容的时候它是间接扩容两倍的,比方当初有 10 个元素,要扩容的时候,就会将数组的大小增长到 20”
面试官:“嗯,那如果咱们不必 Vector,线程平安的 List 还有什么?”
三歪:“首先,咱们也能够用 Collections 来将 ArrayList 来包装一下,变成线程平安。但这必定不是你想听的,对吧。在 java.util.concurrent
包下还有一个类,叫做 CopyOnWriteArrayList”
面试官:“嗯,你持续说”
三歪:“要讲 CopyOnWriteArrayList 之前,我还是想说说 copy-on-write
这个意思,上面我会简称为 cow
。比如说在 Linux 中,咱们晓得所有的过程都是init
过程 fork
进去的,除了过程号之外,fork
进去的过程,默认跟父过程截然不同的。在 fork
之后 exec
之前,两个过程用的是雷同的内存空间的,这意味着子过程的代码段、数据段、堆栈都是 指向 父过程的物理空间”
面试官:“嗯”
三歪:“当父子过程中有更改的行为产生时,再为子过程调配相应物理空间。这样做的益处就是,等到真正产生批改的时候,才去分配资源,能够缩小调配或者复制大量资源时带来的 霎时延时。简略来说,就能够了解为咱们的懒加载,或者说单例模式的懒汉式。等真正用到的时候再调配”
面试官:“嗯”
三歪:“在文件系统中,其实也有 cow
的机制。文件系统的 cow
就是在批改数据的时候,不会间接在原来的数据地位上进行操作,而是从新找个地位批改。比如说:要批改数据块 A 的内容,先把 A 读出来,写到 B 块外面去。如果这时候断电了,原来 A 的内容还在。这样做的益处就是能够保证数据的完整性,霎时挂掉了容易 复原。
三歪:“再回头来看 CopyOnWriteArrayList 吧,CopyOnWriteArrayList 是一个线程平安的 List,底层是通过 复制数组 的形式来实现的。
三歪:“我来说说它 的 add()
办法的实现吧”
面试官:“好”
三歪:“在 add()
办法其实他会加 lock
锁,而后会复制出一个新的数组,往新的数组里边 add
真正的元素,最初把 array 的指向扭转为新的数组”
三歪:“其实 get()
办法又或是 size()
办法只是获取 array 所指向的数组的元素或者大小。读不加锁,写加锁”
三歪:“能够发现的是,CopyOnWriteArrayList 跟文件系统的 COW 机制是很像的”
面试官:“那你能说说 CopyOnWriteArrayList 有什么毛病吗?”
三歪:“很显然,CopyOnWriteArrayList 是很消耗内存的,每次 set()/add()
都会复制一个数组进去,另外就是 CopyOnWriteArrayList 只能保证数据的 最终一致性,不能保证数据的实时一致性。假如两个线程,线程 A 去读取 CopyOnWriteArrayList 的数据,还没读完,当初线程 B 把这个 List 给清空了,线程 A 此时还是能够把残余的数据给读出来。”
面试官:“嗯,还能够,明天的面试就到这里完结了,你有什么想问我的吗?”
三歪:“你感觉我明天的体现怎么样?”
面试官:“明天的体现还能够,如果这一次你没有 100 个 点赞 ,预计 HR 就不会再分割你了。如果超过 100 个 点赞,第二轮好好体现吧。”
面试官:“给你走漏一下,Map 汇合能够好好筹备一下,下一轮将会考查 Map 的常识”
题外话
List 汇合总体来说不会太难,但 CopyOnWriteArrayList 可能很多同学还不晓得有这么一个类。
针对这次的面试可能你想理解更多 List 的细节,比如说 ArrayList/LinkedList/CopyOnWriteArrayList
的源码以及下面提到的 COW
机制,能够在公众号下回复「List」即可获取我之前写的 原创 文章。
须要 预习 或者支付电子书的同学,在公众号下回复「888」即可获取。
本文有配套的 视频 观看:https://www.bilibili.com/video/BV1nT4y1L71r/ 欢送 三连。
各类知识点总结
上面的文章都有对应的 原创精美PDF,在继续更新中,能够来找我催更~
- 92 页的 Mybatis
- 129 页的多线程
- 141 页的 Servlet
- 158 页的 JSP
- 76 页的汇合
- 64 页的 JDBC
- 105 页的数据结构和算法
- 142 页的 Spring
- 58 页的过滤器和监听器
- 30 页的 HTTP
- 42 页的 SpringMVC
- Hibernate
- AJAX
- Redis
- ……
涵盖 Java 后端所有知识点的开源我的项目(已有 10K+ star):
- GitHub
- Gitee 拜访更快
如果大家想要 实时 关注我更新的文章以及分享的干货的话,微信搜寻Java3y。
PDF 文档的内容 均为手打 ,有任何的不懂都能够间接 来问我(公众号有我的联系方式)。
我是三歪,一个想要变强的男人,感激大家的点赞珍藏和转发,下期见。给三歪点个赞,对三歪真的十分重要!