求求大廠給個Offer:List面試題
- 2020 年 8 月 21 日
- 筆記
前言
只有光頭才能變強。
文本已收錄至我的GitHub精選文章,歡迎Star://github.com/ZhongFuCheng3y/3y
從今天開始,我,三歪,正式開始寫面試系列。我給這個面試系列取了一個名字,叫做《求求大廠給個Offer》
上一篇就叫做《求求大廠給個Offer:如何寫簡歷》
所以這篇文章叫做《求求大廠給個Offer:List面試題》
接下來就開始吧。
本文有配套的影片觀看://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」即可獲取。
本文有配套的影片觀看://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):
如果大家想要實時關注我更新的文章以及分享的乾貨的話,微信搜索Java3y。
PDF文檔的內容均為手打,有任何的不懂都可以直接來問我(公眾號有我的聯繫方式)。
我是三歪,一個想要變強的男人,感謝大家的點贊收藏和轉發,下期見。給三歪點個贊,對三歪真的非常重要!