你知道的越多,你不知道的越多git
點贊再看,養成習慣程序員
本文 GitHub github.com/JavaFamily 已收錄,有一線大廠面試點思惟導圖,也整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。github
做爲一個在互聯網公司面一次拿一次Offer的麪霸,戰勝了無數競爭對手,每次都只能看到無數落寞的身影失望的離開,略感愧疚(請容許我使用一下誇張的修辭手法)。面試
因而在一個寂寞難耐的夜晚,我痛定思痛,決定開始寫互聯網技術棧面試相關的文章,但願能幫助各位讀者之後面試勢如破竹,對面試官進行360°的反擊,吊打問你的面試官,讓一同面試的同僚瞠目結舌,瘋狂收割大廠Offer!算法
全部文章的名字只是個人噱頭,咱們應該有一顆謙遜的心,因此但願你們懷着空杯心態好好學,一塊兒進步。數組
一個婀娜多姿,穿着襯衣的小姐姐,拿着一個精緻的小筆記本,徑直走過來坐在個人面前。緩存
看着眼前這個美麗的女人,心想這不會就是Java基礎系列的面試官吧,真香。安全
不過看樣子這麼年輕應該問不出什麼深度的吧,嘻嘻。(哦?是麼😏)微信
帥丙,上次面試到如今都過去2個星期你纔過來,爲啥鴿了這麼久?數據結構
美麗迷人的面試官您好,由於以前得了流感,差點就沒了,還有最近年末忙年會和年終review的事情,實在太忙了,很差意思。
還作了一波導演(實際上是打雜)去拍攝蘑菇街的年會視頻了,實在忙到爆炸,週末也沒能懟出文章哈哈。
好吧那我理解了,下次這種狀況記得提早跟我說,對了,多喝熱水。
面試官最後的多喝熱水,直接觸動我心裏的防線,竟然還有人這麼關心我,帥丙的眼角,又溼了……
ArrayList有用過嗎?它是一個什麼東西?能夠用來幹嗎?
有用過,ArrayList就是數組列表,主要用來裝載數據,當咱們裝載的是基本類型的數據int,long,boolean,short,byte…的時候咱們只能存儲他們對應的包裝類,它的主要底層實現是數組Object[] elementData。
與它相似的是LinkedList,和LinkedList相比,它的查找和訪問元素的速度較快,但新增,刪除的速度較慢。
小結:ArrayList底層是用數組實現的存儲。
特色:查詢效率高,增刪效率低,線程不安全。使用頻率很高。
爲啥線程 不安全還使用他呢?
由於咱們正常使用的場景中,都是用來查詢,不會涉及太頻繁的增刪,若是涉及頻繁的增刪,可使用LinkedList,若是你須要線程安全就使用Vector,這就是三者的區別了,實際開發過程當中仍是ArrayList使用最多的。
不存在一個集合工具是查詢效率又高,增刪效率也高的,還線程安全的,至於爲啥你們看代碼就知道了,由於數據結構的特性就是優劣共存的,想找個平衡點很難,犧牲了性能,那就安全,犧牲了安全那就快速。
Tip:這裏仍是強調下你們不要爲了用而用,我記得我之前最開始工做就有這個毛病。就是無論三七二十一,就是爲了用而用,別人用我也用,也無論他的性能啊,是否線程安全啥的,所幸最開始公司接觸的,都是線下的系統,並且沒啥併發。
如今回想起來還有點後怕,並且我第一次出去面試就被一個算法的大佬給虐得體無完膚,其實他問的我都會用,可是就是說不上來爲啥用,爲啥這麼作。
回想起一年前的第一次面試,我又想到了那時候的點滴,那時候我身邊還有女人,那時候我還有頭髮,那時候……個人眼角又溼了。
您說它的底層實現是數組,可是數組的大小是定長的,若是咱們不斷的往裏面添加數據的話,不會有問題嗎?
ArrayList能夠經過構造方法在初始化的時候指定底層數組的大小。
經過無參構造方法的方式ArrayList()初始化,則賦值底層數Object[] elementData爲一個默認空數組Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}因此數組容量爲0,只有真正對數據進行添加add時,才分配默認DEFAULT_CAPACITY = 10的初始容量。
你們能夠分別看下他的無參構造器和有參構造器,無參就是默認大小,有參會判斷參數。
數組的長度是有限制的,而ArrayList是能夠存聽任意數量對象,長度不受限制,那麼他是怎麼實現的呢?
其實實現方式比較簡單,他就是經過數組擴容的方式去實現的。
就好比咱們如今有一個長度爲10的數組,如今咱們要新增一個元素,發現已經滿了,那ArrayList會怎麼作呢?
第一步他會從新定義一個長度爲10+10/2的數組也就是新增一個長度爲15的數組。
而後把原數組的數據,原封不動的複製到新數組中,這個時候再把指向原數的地址換到新數組,ArrayList就這樣完成了一次改頭換面。
Tip:不少小夥伴說,你舉例幹嗎用10這麼長的數組舉例,這樣畫都要多畫一點格子了,帥丙我會作無心義的事情?由於咱們在使用ArrayList的時候通常不會設置初始值的大小,那ArrayList默認的大小就恰好是10。
而後大家也能夠看到,他的構造方法,若是你傳入了初始值大小,那就使用你傳入的參數,若是沒,那就使用默認的,一切都是有跡可循的。
能具體說下1.7和1.8版本初始化的時候的區別麼?
arrayList1.7開始變化有點大,一個是初始化的時候,1.7之前會調用this(10)纔是真正的容量爲10,1.7即自己之後是默認走了空數組,只有第一次add的時候容量會變成10。
ArrayList的默認數組大小爲何是10?
其實我也沒找到具體緣由。
聽說是由於sun的程序員對一系列普遍使用的程序代碼進行了調研,結果就是10這個長度的數組是最經常使用的最有效率的。也有說就是隨便起的一個數字,8個12個都沒什麼區別,只是由於10這個數組比較的圓滿而已。
我記得你說到了,他增刪很慢,你能說一下ArrayList在增刪的時候是怎麼作的麼?主要說一下他爲啥慢。
誒臥*,這個我想一下,大學看的有點忘記了,我想一想。
嗯嗯好的,我分別說一下他的新增的邏輯吧。
他有指定index新增,也有直接新增的,在這以前他會有一步校驗長度的判斷ensureCapacityInternal,就是說若是長度不夠,是須要擴容的。
在擴容的時候,老版本的jdk和8之後的版本是有區別的,8以後的效率更高了,採用了位運算,右移一位,其實就是除以2這個操做。
1.7的時候3/2+1 ,1.8直接就是3/2。
指定位置新增的時候,在校驗以後的操做很簡單,就是數組的copy,你們能夠看下代碼。
不知道你們看懂arraycopy的代碼沒有,我畫個圖解釋下,你可能就明白一點:
好比有下面這樣一個數組我須要在index 5的位置去新增一個元素A
那從代碼裏面咱們能夠看到,他複製了一個數組,是從index 5的位置開始的,而後把它放在了index 5+1的位置
給咱們要新增的元素騰出了位置,而後在index的位置放入元素A就完成了新增的操做了
至於爲啥說他效率低,我想我不說你也應該知道了,我這只是在一個這麼小的List裏面操做,要是我去一個幾百幾千幾萬大小的List新增一個元素,那就須要後面全部的元素都複製,而後若是再涉及到擴容啥的就更慢了不是嘛。
我問你個真實的場景,這個問題不多人知道,你可要好好回答喲!
ArrayList(int initialCapacity)會不會初始化數組大小?
這是什麼問題?臥槽問個ArrayList還能問到知識盲區?
不要慌,我記得丙丙說過:不管咱們遇到什麼困難都不要懼怕,打敗恐懼最好的辦法就是面對他!!!奧利給!!!…
會初始化數組大小!可是List的大小沒有變,由於list的大小是返回size的。
並且將構造函數與initialCapacity結合使用,而後使用set()會拋出異常,儘管該數組已建立,可是大小設置不正確。
使用sureCapacity()也不起做用,由於它基於elementData數組而不是大小。
還有其餘反作用,這是由於帶有sureCapacity()的靜態DEFAULT_CAPACITY。
進行此工做的惟一方法是在使用構造函數後,根據須要使用add()屢次。
你們可能有點懵,我直接操做一下代碼,你們會發現咱們雖然對ArrayList設置了初始大小,可是咱們打印List大小的時候仍是0,咱們操做下標set值的時候也會報錯,數組下標越界。
其實數組是初始化了,可是List沒,那size就沒變,set下標是和size比較的那就報錯了。
再結合源碼,你們仔細品讀一下,這是Java Bug裏面的一個經典問題了,仍是頗有意思的,你們平時可能也不會注意這個點。
ArrayList插入刪除必定慢麼?
取決於你刪除的元素離數組末端有多遠,ArrayList拿來做爲堆棧來用仍是挺合適的,push和pop操做徹底不涉及數據移動操做。
那他的刪除怎麼實現的呢?
刪除其實跟新增是同樣的,不過叫是叫刪除,可是在代碼裏面咱們發現,他仍是在copy一個數組。
爲啥是copy數組呢?
繼續打個比方,咱們如今要刪除下面這個數組中的index5這個位置
那代碼他就複製一個index5+1開始到最後的數組,而後把它放到index開始的位置
index5的位置就成功被」刪除「了其實就是被覆蓋了,給了你被刪除的感受。
同理他的效率也低,由於數組若是很大的話,同樣須要複製和移動的位置就大了。
ArrayList是線程安全的麼?
固然不是,線程安全版本的數組容器是Vector。
Vector的實現很簡單,就是把全部的方法通通加上synchronized就完事了。
你也能夠不使用Vector,用Collections.synchronizedList把一個普通ArrayList包裝成一個線程安全版本的數組容器也能夠,原理同Vector是同樣的,就是給全部的方法套上一層synchronized。
ArrayList用來作隊列合適麼?
隊列通常是FIFO(先入先出)的,若是用ArrayList作隊列,就須要在數組尾部追加數據,數組頭部刪除數組,反過來也能夠。
可是不管如何總會有一個操做會涉及到數組的數據搬遷,這個是比較耗費性能的。
結論:ArrayList不適合作隊列。
那數組適合用來作隊列麼?
這個女人是魔鬼麼?不過仍是得微笑面對!
數組是很是合適的。
好比ArrayBlockingQueue內部實現就是一個環形隊列,它是一個定長隊列,內部是用一個定長數組來實現的。
另外著名的Disruptor開源Library也是用環形數組來實現的超高性能隊列,具體原理不作解釋,比較複雜。
簡單點說就是使用兩個偏移量來標記數組的讀位置和寫位置,若是超過長度就折回到數組開頭,前提是它們是定長數組。
ArrayList的遍歷和LinkedList遍歷性能比較如何?
論遍歷ArrayList要比LinkedList快得多,ArrayList遍歷最大的優點在於內存的連續性,CPU的內部緩存結構會緩存連續的內存片斷,能夠大幅下降讀取內存的性能開銷。
能跟我聊一下LinkedList相關的東西麼?
能夠呀,否則今每天色已晚,否則咱們下次再聊?
好吧,每次你都找藉口,下次能夠集合最後章節了,咱們好好聊聊,你好好準備吧。
ArrayList就是動態數組,用MSDN中的說法,就是Array的複雜版本,它提供了動態的增長和減小元素,實現了ICollection和IList接口,靈活的設置數組的大小等好處。
面試裏面問的時候沒HashMap,ConcurrentHashMap啥的這麼常問,可是也有必定機率問到的,仍是那句話,不打沒把握的仗。
咱們在源碼閱讀過程當中,不須要所有都讀懂,須要作的就是讀懂核心的源碼,加深本身對概念的理解就行了,用的時候不至於啥都不知道,不要爲了用而用就行了。
將指定的元素添加到此列表的尾部。
將指定的元素插入此列表中的指定位置。
按照指定 collection 的迭代器所返回的元素順序,將該 collection 中的全部元素添加到此列表的尾部。
從指定的位置開始,將指定 collection 中的全部元素插入到此列表中。
移除此列表中的全部元素。
返回此 ArrayList 實例的淺表副本。
若是此列表中包含指定的元素,則返回 true。
若有必要,增長此 ArrayList 實例的容量,以確保它至少可以容納最小容量參數所指定的元素數。
返回此列表中指定位置上的元素。
返回此列表中首次出現的指定元素的索引,或若是此列表不包含元素,則返回 -1。
若是此列表中沒有元素,則返回 true
返回此列表中最後一次出現的指定元素的索引,或若是此列表不包含索引,則返回 -1。
移除此列表中指定位置上的元素。
移除此列表中首次出現的指定元素(若是存在)。
移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之間的全部元素。
用指定的元素替代此列表中指定位置上的元素。
返回此列表中的元素數。
按適當順序(從第一個到最後一個元素)返回包含此列表中全部元素的數組。
按適當順序(從第一個到最後一個元素)返回包含此列表中全部元素的數組;返回數組的運行時類型是指定數組的運行時類型。
將此 ArrayList 實例的容量調整爲列表的當前大小。
好了各位,以上就是這篇文章的所有內容了,能看到這裏的人呀,都是人才。
我後面會每週都更新幾篇一線互聯網大廠面試和經常使用技術棧相關的文章,很是感謝人才們能看到這裏,若是這個文章寫得還不錯,以爲「敖丙」我有點東西的話 求點贊👍 求關注❤️ 求分享👥 對暖男我來講真的 很是有用!!!
白嫖很差,創做不易,各位的支持和承認,就是我創做的最大動力,咱們下篇文章見!
敖丙 | 文 【原創】
若是本篇博客有任何錯誤,請批評指教,不勝感激 !
文章每週持續更新,能夠微信搜索「 三太子敖丙 」第一時間閱讀和催更(比博客早一到兩篇喲),本文 GitHub github.com/JavaFamily 已經收錄,有一線大廠面試點思惟導圖,也整理了不少個人文檔,歡迎Star和完善,你們面試能夠參照考點複習,但願咱們一塊兒有點東西。