java集合之ArrayList
相信大家在日常生活開發中,接觸的集合當中,ArrayList是大家經常會用到的, 但是想要在碼界立足,只是單純的應用已經滿足不了現在的需求了,誰不懷念當初大學在校園操場上牽著好多小妹妹的手在遛彎,好了,不多說了,淚水已經打濕了我的眼眶…(要說裝逼這方面,我們誰不會,哈哈…,傻瓜,好好學技術),進入正題,
一:什么是ArrayList
大家應該都知道,他的底層其實就是一個陣列結構的,當我們在使用list的時候相比大家都是直接類似new ArrayList<>(), 這種方式來進行創建,我們在new的時候會發生什么呢?(這里只針對JDK1.8來說)
大家都明白ArrayList的初始容量是10, 但是這個10是什么時候給的呢?我們明明new的空的list,咋會是10呢?難道new初始化的時候會直接給容量嗎?我們繼續看

顯然不是new的時候給的,那么當我add的時候呢?這里我先直接給你上add時的原始碼圖

這里面的size屬性,是成員變數,大家都知道new物件的時候,有一步是對變數賦默認值,暖心的我在這里幫你們回憶一下,new物件的時候會發生什么,首先第一步會判斷對應的類是否已經加載、連接、初始化(這里是當虛擬機遇到new指令的時候,他會去metaSpace找對應的類的符號參考,檢查這個符號參考是否已經加載、連接、初始化);第二步會在堆中給他開辟一個記憶體空間(注意這里會處理并發安全問題,一般會采用cas失敗重試機制,區域加鎖保證更新原子性和每個執行緒預先分配一塊TLAB,默認下TLAB一般占eden的1%;第三步會去默認初始化;第四步設定物件頭;第五步執行init方法初始化,
好了我們繼續,所以此時size=0, 然后我們進入ensureCapacityInternal方法,

這個方法里有calculateCapacity方法,我們再進去

到這里我們是不是很明白了,elementData是空,進入if,DEFAULT_CAPACITY是10,在類成員中定義的,接著我們看ensureExplicitCapacity方法,此時入參是10

modCount++,這個有得很關鍵,下面我回說到;if里會有一個grow操作,我們繼續看一下這個方法如下:

相信大家看到這知道這個是在干嘛了吧,minCapacity是10,然后我們通過把oldCapacity陣列擴大為原來的1.5倍,這里采用的右移位,如果newCapacity的容量此時與minCapacity做差,小于0就是賦值minCapacity給newCapacity,
Arrays.copyOf(elementData, newCapacity);這個操作是將elementData值放到一個新陣列里,新陣列的長度大小是newCapacity,然后我們再回到剛才的add方法,elementData[size++] = e;是將你此時add的元素放在陣列中,此時add操作完成,這就是給集合添加元素的流程,
二:例外問題(ConcurrentModificationException)
由于公司代碼保密原因,這里我只是用案例模擬下:

這是用iterator迭代器來遍歷集合,如果發現值是2,就對list進行一個remove操作,這里大家感覺邏輯沒問題,但是會報并發修改例外,我們來揭秘下,
首先list.iterator()方法里面就是直接 new Itr(),我們看下Itr()方法

里面有三個引數cursor(遍歷當前元素的下標值),lastRet(遍歷當前元素的下標的前一個值),expectedModCount = modCount(我前面說過modCount很重要…,在這里邊表現,代表修改的次數,比如上面add就會對他+1,每對集合修改一次,就會+1,注意此時上面我們add了兩次,所以modCount為2,expectedModCount為2),當我們呼叫hasNext方法時候,cursor != size()這個判斷意思是,cursor集合當前下標如果不等于集合長度,證明集合中會有資料,我們就允許去獲取值,然后就是 iterator.next()方法我們在來剖析

checkForComodification這個方法我們先不去看,看下面的,將cursor復制給i,然后獲取資料回傳,然后我們判斷如果這個值是2,我們上面就會進行remove操作,我們看下這個操作原始碼

最侄訓起執行fastRemove方法,移除元素,可不是直接remove的值啊,最侄訓是根據值去尋找的下標然后我們去remove的下標,我們再進去fastRemove方法,

這里modCount又進行了加++操作,此時modCount為3,我們繼續往下看
int numMoved = size - index - 1,這里其實就是尋找的你洗掉的元素的下標之后的元素個數,如果numMoved 是大于0的,我們會進行 System.arraycopy操作,這個操作不用我多解釋吧?其實就是對陣列進行了一個復制操作,這里最后
elementData[–size] = null這個操作也許你看到以后會說,這是什么傻逼操作,為啥還給弄成null(淚水再一次打濕我的眼眶…),是的,這里為null,是有意義的,是為了讓他及時進行垃圾回收,釋放空間,你想,洗掉操作其實就是對后面的元素進行復制到原陣列,那我們陣列里最后一個元素的空間是不是還會被一直占用啊?這就是典型的記憶體泄漏,舉個例子就是占著茅坑不拉屎,你想憋死他們啊…,
好了,你吹了這么多牛逼,那這個例外發生的點在哪呢?不裝逼了,往下看,大家還記得我說的checkForComodification方法嗎?我們進去看一下

臥槽!!! 一目了然,這里回圈的時候再進行下一次next的時候,會判斷這兩個數相不相等,不相等就會拋出例外,上面modCount是3,expectedModCount是2,顯然不等,所以報錯,

寫到這里大家估計能了解到這個ArrayList東西了吧,哪里有不對的地方歡迎大家指導,虛心求學,我經常有一句話,不奮斗的人生是沒有任何意義的,我們共同加油,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/279547.html
標籤:其他
下一篇:ARP欺騙原理及實驗
