求求大厂给个Offer:List面试题

前言

只有光头才能变强。

文本已收录至个人GitHub精选文章,欢迎Starhttps://github.com/ZhongFuCheng3y/3yjava

从今天开始,我,三歪,正式开始写面试系列。我给这个面试系列取了一个名字,叫作《求求大厂给个Offer》git

上一篇就叫作《求求大厂给个Offer:如何写简历》github

因此这篇文章叫作《求求大厂给个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,在持续更新中,能够来找我催更~

涵盖Java后端全部知识点的开源项目(已有10K+ star):

若是你们想要实时关注我更新的文章以及分享的干货的话,微信搜索Java3y

PDF文档的内容均为手打,有任何的不懂均可以直接来问我(公众号有个人联系方式)。

我是三歪,一个想要变强的男人,感谢你们的点赞收藏和转发,下期见。给三歪点个赞,对三歪真的很是重要!