前言
微信搜【Java3y】關注這個有夢想的男人才顿,點贊關注是對我最大的支持勇婴!
文本已收錄至我的GitHub:https://github.com/ZhongFuCheng3y/3y,有300多篇原創(chuàng)文章盆偿,最近在連載面試系列求橄!
從今天開始灵巧,我欢搜,三歪,正式開始寫面試系列滚局。我給這個面試系列取了一個名字,叫做《求求大廠給個Offer》
上一篇就叫做《求求大廠給個Offer:如何寫簡歷》
所以這篇文章叫做《求求大廠給個Offer:List面試題》
接下來就開始吧嘁圈。
本文有配套的視頻觀看:https://www.bilibili.com/video/BV1nT4y1L71r/ 歡迎三連最住。
面試現(xiàn)場
面試官:“你先簡單自我介紹吧涨缚∨海”
三歪:“我叫三歪茂翔,目前維護一個公眾號叫做Java3y惭嚣,這幾年寫了300+原創(chuàng)技術文章晚吞,近1000頁的原創(chuàng)電子書和多個知識點的思維導圖载矿。我的愿景是:只要關注我并三連的同學都可以拿到大廠offer。我的....”
面試官:“停停停逢勾,別吹了溺拱,我們正式開始吧迫摔【湔迹”
面試官:“來講講Java的List吧,你對List了解多少擂啥?”
三歪:“List在Java里邊是一個接口哺壶,常見的實現(xiàn)類有ArrayList和LinkedList山宾,在開發(fā)中用得最多的是ArrayList”
面試官:“你再分別來講講ArrayList和LinkedList的區(qū)別唄”
三歪:“ArrayList的底層數據結構是數組渊胸,LinkedList底層數據結構是鏈表。”
面試官:“那我們本身就有數組了萨咳,為什么要用ArrayList呢鹃两?”
三歪:“原生的數組會有一個特點:你在使用的時候必須要為它創(chuàng)建大小俊扳,而ArrayList不用”
面試官:“那你說說ArrayList是怎么實現(xiàn)的吧,為什么ArrayList就不用創(chuàng)建大小呢懊烤?”
三歪:“其實是這樣的茸习,我看過源碼逮光。當我們new ArrayList()
的時候涕刚,默認會有一個空的Object
數組,大小為0驾茴。當我們第一次add
添加數據的時候锈至,會給這個數組初始化一個大小峡捡,這個大小默認值為10”
面試官:“嗯”
三歪:“還有就是稍途,數組的大小是固定的械拍,而ArrayList的大小是可變的”
面試官:“那怎么理解固定和可變的呢坷虑?你說說看”
三歪:“假設我們給定數組的大小是10,要往這個數組里邊填充元素海蔽,我們只能添加10個元素党窜。而ArrayList不一樣幌衣,ArrayList我們在使用的時候可以往里邊添加20個,30個楚里,甚至更多的元素”
三歪:“因為ArrayList是實現(xiàn)了動態(tài)擴容的”
面試官:“那它是怎么實現(xiàn)的呢班缎?”
三歪:“使用ArrayList在每一次add
的時候,它都會先去計算這個數組夠不夠空間趁耗,如果空間是夠的满葛,那直接追加上去就好了纱扭。如果不夠乳蛾,那就得擴容”
面試官:“那怎么擴容?一次擴多少因惭?”
三歪:“在源碼里邊,有個grow
方法姻成,每一次擴原來的1.5
倍低缩。比如說咆繁,初始化的值是10嘛⊥姘悖現(xiàn)在我第11個元素要進來了,發(fā)現(xiàn)這個數組的空間不夠了久脯,所以會擴到15”
三歪:“空間擴完容之后帘撰,會調用arraycopy
來對數組進行拷貝”
面試官:“哦摧找,可以的芝雪。那為什么你在前面提到惩系,在日常開發(fā)中用得最多的是ArrayList呢堡牡?”
三歪:“是由底層的數據結構來決定的,在日常開發(fā)中芥颈,遍歷的需求比增刪要多浇借,即便是增刪也是往往在List的尾部添加就OK了妇垢。像在尾部添加元素,ArrayList的時間復雜度也就O(1)
”
三歪:“另外的是涨薪,ArrayList的增刪底層調用的copyOf()
被優(yōu)化過刚夺,現(xiàn)代CPU對內存可以塊操作侠姑,ArrayList的增刪一點兒也不會比LinkedList慢”
面試官:“Vector你了解嗎?”
三歪:“嗯安吁,Vector是底層結構是數組网棍,一般現(xiàn)在我們已經很少用了滥玷。相對于ArrayList,它是線程安全的拉盾,在擴容的時候它是直接擴容兩倍的,比如現(xiàn)在有10個元素夭禽,要擴容的時候讹躯,就會將數組的大小增長到20”
面試官:“嗯潮梯,那如果我們不用Vector,線程安全的List還有什么萝究?”
三歪:“首先帆竹,我們也可以用Collections來將ArrayList來包裝一下馆揉,變成線程安全舷暮。但這肯定不是你想聽的下面,對吧沥割。在java.util.concurrent
包下還有一個類,叫做CopyOnWriteArrayList”
面試官:“嗯椒拗,你繼續(xù)說”
三歪:“要講CopyOnWriteArrayList之前蚀苛,我還是想說說copy-on-write
這個意思堵未,下面我會簡稱為cow
。比如說在Linux中拙徽,我們知道所有的進程都是init
進程fork
出來的膘怕,除了進程號之外岛心,fork
出來的進程,默認跟父進程一模一樣的髓堪。在fork
之后exec
之前干旁,兩個進程用的是相同的內存空間的争群,這意味著子進程的代碼段玉雾、數據段复旬、堆棧都是指向父進程的物理空間”
面試官:“嗯”
三歪:“當父子進程中有更改的行為發(fā)生時驹碍,再為子進程分配相應物理空間幸冻。這樣做的好處就是,等到真正發(fā)生修改的時候革半,才去分配資源,可以減少分配或者復制大量資源時帶來的瞬間延時漫试。簡單來說外构,就可以理解為我們的懶加載审编,或者說單例模式的懶漢式垒酬。等真正用到的時候再分配”
面試官:“嗯”
三歪:“在文件系統(tǒng)中矮湘,其實也有cow
的機制板祝。文件系統(tǒng)的cow
就是在修改數據的時候,不會直接在原來的數據位置上進行操作橘洞,而是重新找個位置修改炸枣。比如說:要修改數據塊A的內容适肠,先把A讀出來,寫到B塊里面去澄干。如果這時候斷電了辩稽,原來A的內容還在逞泄。這樣做的好處就是可以保證數據的完整性喷众,瞬間掛掉了容易恢復侮腹。
三歪:“再回頭來看CopyOnWriteArrayList吧愈涩,CopyOnWriteArrayList是一個線程安全的List履婉,底層是通過復制數組的方式來實現(xiàn)的毁腿。
三歪:“我來說說它 的add()
方法的實現(xiàn)吧”
面試官:“好”
三歪:“在add()
方法其實他會加lock
鎖,然后會復制出一個新的數組胯究,往新的數組里邊add
真正的元素裕循,最后把array的指向改變?yōu)樾碌臄到M”
三歪:“其實get()
方法又或是size()
方法只是獲取array所指向的數組的元素或者大小。讀不加鎖株婴,寫加鎖”
三歪:“可以發(fā)現(xiàn)的是督暂,CopyOnWriteArrayList跟文件系統(tǒng)的COW機制是很像的”
面試官:“那你能說說CopyOnWriteArrayList有什么缺點嗎饥努?”
三歪:“很顯然驾诈,CopyOnWriteArrayList是很耗費內存的乍迄,每次set()/add()
都會復制一個數組出來闯两,另外就是CopyOnWriteArrayList只能保證數據的最終一致性重慢,不能保證數據的實時一致性似踱。假設兩個線程,線程A去讀取CopyOnWriteArrayList的數據狞洋,還沒讀完吉懊,現(xiàn)在線程B把這個List給清空了借嗽,線程A此時還是可以把剩余的數據給讀出來〔沂伲”
面試官:“嗯,還可以删窒,今天的面試就到這里結束了裂垦,你有什么想問我的嗎?”
三歪:“你覺得我今天的表現(xiàn)怎么樣肌索?”
面試官:“今天的表現(xiàn)還可以蕉拢,如果這一次你沒有100個點贊,估計HR就不會再聯(lián)系你了诚亚。如果超過100個點贊晕换,第二輪好好表現(xiàn)吧夷家。”
面試官:“給你透露一下,Map集合可以好好準備一下,下一輪將會考察Map的知識”
題外話
List集合總體來說不會太難,但CopyOnWriteArrayList可能很多同學還不知道有這么一個類所踊。
針對這次的面試可能你想了解更多List的細節(jié)继薛,比如說ArrayList/LinkedList/CopyOnWriteArrayList
的源碼以及上面提到的COW
機制诈皿,可以在公眾號下回復「List」即可獲取我之前寫的原創(chuàng)文章胖腾。
需要預習或者領取電子書的同學,在公眾號下回復「888」即可獲取。
本文有配套的視頻觀看:https://www.bilibili.com/video/BV1nT4y1L71r/ 歡迎三連郑趁。
涵蓋Java后端所有知識點的開源項目舅柜,已有10K+ star瞬沦!內含1000+頁原創(chuàng)電子書!A履辍区拳!
PDF文檔的內容均為手打业汰,有任何的不懂都可以直接來問我