7

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

 3 years ago
source link: https://zhuanlan.zhihu.com/p/200879006
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

公众号:Java3y

微信搜【Java3y】关注这个有梦想的男人,点赞关注是对我最大的支持!
文本已收录至我的GitHubhttps://github.com/ZhongFuCheng3y/3y,有300多篇原创文章,最近在连载面试系列!

从今天开始,我,三歪,正式开始写面试系列。我给这个面试系列取了一个名字,叫做《求求大厂给个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机制

☕ 各类知识点总结

下面的文章都有对应的原创精美PDF,在持续更新中,可以来找我催更~

三歪把【大厂面试知识点】、【简历模板】、【原创文章】全部整理成电子书,共有1263页!点击下方链接直接取就好了

ZhongFuCheng3y/3y​github.com

收藏等于白嫖,点赞才是真情!

收藏等于白嫖,点赞才是真情!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK