基于java構(gòu)造方法Vector刪除元素源碼分析
(注意:本文基于JDK1.8)
前言
包括迭代器中的remove()方法,以及刪除單個(gè)元素、刪除多個(gè)元素、刪除所有元素、刪除不包含的所有元素的方法,Vector中共計(jì)10個(gè)對(duì)外的API可以用于刪除元素,今天一起分析每一個(gè)刪除元素的方法是如何實(shí)現(xiàn)的!
remove(int)方法分析
public synchronized E remove(int index) { modCount++; if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); E oldValue = elementData(index); int numMoved = elementCount - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--elementCount] = null; // Let gc do its work return oldValue; }
用于刪除指定下標(biāo)單個(gè)元素的方法,傳入的參數(shù)index表示元素的下標(biāo),第一個(gè)元素的下標(biāo)是0,這個(gè)基礎(chǔ)知識(shí)點(diǎn)不要忘記哦
1、為fail-fast機(jī)制保駕護(hù)航
modCount是Vector對(duì)象持有的一個(gè)int變量,它本身位于Vector的父類AbstractList中,此處增加1,表示Vector的元素狀態(tài)發(fā)生改變,迭代器那里會(huì)使用fail-fast,防止多線程下即遍歷又刪除,也防止單線程下,一邊遍歷元素、一邊刪除元素
2、檢查下標(biāo)是否存在元素
檢查傳入的下標(biāo)index是否存在元素,當(dāng)index與elementCount相等或者大于elementCount,此處的index并沒有元素,所以不能刪除沒有元素的位置,此處作者拋出ArrayIndexOutOfBoundsException對(duì)象,為此告知調(diào)用者,你傳入的下標(biāo)根本沒有元素,怎么刪除呢?
3、保存刪除的元素到局部變量
調(diào)用elementData元素,并傳入下標(biāo)index,獲得指定下標(biāo)處的元素,并由局部變量oldValue負(fù)責(zé)保存
4、計(jì)算需要挪動(dòng)元素的數(shù)量
使用表示元素總數(shù)的elementCount減去index、減去1,得到需要挪動(dòng)元素的數(shù)量并存儲(chǔ)到局部變量numMoved
5、挪動(dòng)元素
如果需要挪動(dòng)元素,就將index下標(biāo)后面的所有元素向前挪動(dòng)(復(fù)制)
6、減少元素總數(shù)值
先將元素總數(shù)elementCount減去1
7、將持有元素的引用,賦值為null
將Vector對(duì)象持有的數(shù)組elementData對(duì)象的指定下標(biāo)處,賦值為null,GC會(huì)刪除沒有Root結(jié)點(diǎn)對(duì)象連接的對(duì)象
8、向調(diào)用者返回刪除后的元素
return會(huì)返回此時(shí)被刪除的元素對(duì)象
remove(Object)方法分析
public boolean remove(Object o) { return removeElement(o); }
用于將第一個(gè)匹配的元素對(duì)象刪除的方法,傳入的參數(shù)為元素對(duì)象,此方法并沒有使用synchronized修飾,那么它如何保證線程安全的刪除元素呢?往下看……
1、實(shí)際調(diào)用removeElement()方法
2、向調(diào)用者返回刪除結(jié)果
removeElement(Object)方法分析
public synchronized boolean removeElement(Object obj) { modCount++; int i = indexOf(obj); if (i >= 0) { removeElementAt(i); return true; } return false; }
用于刪除元素的方法,使用synchronized修飾,同一時(shí)刻只有獲得對(duì)象鎖的線程可以執(zhí)行該方法,未獲得對(duì)象鎖的線程,將被阻塞在方法的入口處,傳入的1個(gè)參數(shù)表示元素對(duì)象
1、fail-fast機(jī)制保護(hù)
modCount增加1,表示Vector持有的元素發(fā)生改變
2、獲取元素對(duì)象在數(shù)組中的下標(biāo)
調(diào)用index()方法,同時(shí)會(huì)將元素對(duì)象ob傳入進(jìn)去,返回值則由局部變量i負(fù)責(zé)存儲(chǔ),它存儲(chǔ)的是元素在數(shù)組中下標(biāo)
3、元素存在,則繼續(xù)執(zhí)行刪除工作
當(dāng)局部變量i的值大于等于0,說明元素存儲(chǔ)在數(shù)組中(Vector對(duì)象持有一個(gè)數(shù)組對(duì)象,用于保存元素的引用),通過調(diào)用removeElement()方法完成刪除工作,最后向調(diào)用者返回true,表示刪除元素成功
4、當(dāng)元素不存在時(shí),向調(diào)用者返回false
removeElementAt(int)方法分析
public synchronized void removeElementAt(int index) { modCount++; if (index >= elementCount) { throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount); } else if (index < 0) { throw new ArrayIndexOutOfBoundsException(index); } int j = elementCount - index - 1; if (j > 0) { System.arraycopy(elementData, index + 1, elementData, index, j); } elementCount--; elementData[elementCount] = null; /* to let gc do its work */ }
用于刪除指定下標(biāo)的元素,使用synchronized修飾,同一時(shí)刻只有1個(gè)線程可以執(zhí)行該方法,其它未獲得對(duì)象鎖的線程將被阻塞在入口處,傳入的1個(gè)參數(shù)index表示元素的下標(biāo)
1、fail-fast機(jī)制
modCount增加1,表示Vector保存的元素發(fā)生改變
2、檢查下標(biāo)是否合理
當(dāng)傳入的下標(biāo)index大于等于Vector對(duì)象持有的elementCount值時(shí),拋出ArrayIndexOutOfBoundsException,告知調(diào)用者,index >= xx值
當(dāng)傳入的下標(biāo)index小于0時(shí),同樣拋出ArrayIndexOutOfBoundsException對(duì)象,此時(shí)只告知index值是多少
只有下標(biāo)0至elementCount - 1的范圍內(nèi),才有元素,所以作者的保護(hù)相當(dāng)?shù)暮侠?/p>
3、計(jì)算需要移動(dòng)元素的數(shù)量
比如一共保存了5個(gè)元素(elementCount)、需要?jiǎng)h除下標(biāo)為3的元素,下標(biāo)為3的元素是第4個(gè)元素,后續(xù)需要挪動(dòng)的元素?cái)?shù)量為1,所以
公式為:remove_num = elementCount - index - 1,我們?cè)偬走M(jìn)來公式里:remove_num = 5 - 3 - 1
4、開始挪動(dòng)元素
挪動(dòng)元素,而采用的是復(fù)制元素,system類的靜態(tài)方法arrycopy即可做到,它接受5個(gè)參數(shù)
第一個(gè)參數(shù):表示需要從哪個(gè)數(shù)組對(duì)象中復(fù)制元素(源頭)
第二個(gè)參數(shù):表示需要從數(shù)組對(duì)象的哪個(gè)下標(biāo)處,開始復(fù)制
第三個(gè)參數(shù):表示需要粘貼到哪個(gè)數(shù)組對(duì)象中(目標(biāo))
第四個(gè)參數(shù):表示需要粘貼到數(shù)組對(duì)象的起始下標(biāo)
第五個(gè)參數(shù):表示共計(jì)復(fù)制幾個(gè)元素
5、記錄的元素總數(shù)減去1
elementCount減少1
6、將剩下的數(shù)組中,多余的引用,刪除掉
因?yàn)槊總€(gè)元素都向前復(fù)制了一位,所以此時(shí)的elementCount指向的下標(biāo)處,還存著對(duì)象的引用,這會(huì)造成對(duì)象無法被GC回收,賦值為null,由GC回收對(duì)象占用的內(nèi)存空間
removeIf()方法分析
public synchronized boolean removeIf(Predicate<? super E> filter) { Objects.requireNonNull(filter); // figure out which elements are to be removed // any exception thrown from the filter predicate at this stage // will leave the collection unmodified int removeCount = 0; final int size = elementCount; final BitSet removeSet = new BitSet(size); final int expectedModCount = modCount; for (int i=0; modCount == expectedModCount && i < size; i++) { @SuppressWarnings("unchecked") final E element = (E) elementData[i]; if (filter.test(element)) { removeSet.set(i); removeCount++; } } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } // shift surviving elements left over the spaces left by removed elements final boolean anyToRemove = removeCount > 0; if (anyToRemove) { final int newSize = size - removeCount; for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) { i = removeSet.nextClearBit(i); elementData[j] = elementData[i]; } for (int k=newSize; k < size; k++) { elementData[k] = null; // Let gc do its work } elementCount = newSize; if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } modCount++; } return anyToRemove; }
實(shí)現(xiàn)Collection接口的方法,用于根據(jù)指定條件刪除元素的方法,同樣由synchronized修飾,同一時(shí)刻只有獲取到當(dāng)前對(duì)象鎖的線程可以調(diào)用此方法,其它線程如果也調(diào)用此方法,會(huì)被阻塞在方法的入口處
1、檢查傳入的Predicate對(duì)象
確保Predicate對(duì)象必須傳入,此處使用Objects的靜態(tài)方法requireNonNull()檢查
2、創(chuàng)建用于記錄刪除數(shù)量的局部變量
removeCount,默認(rèn)值為0
3、臨時(shí)存儲(chǔ)當(dāng)前Vector對(duì)象持有的元素總數(shù)
創(chuàng)建一個(gè)局部變量size用于存儲(chǔ)當(dāng)前元素總數(shù)elementCount
4、創(chuàng)建BitSet對(duì)象
利用Vector對(duì)象持有的元素總數(shù)size,用于創(chuàng)建一個(gè)BitSet對(duì)象,局部變量removeSet臨時(shí)指向該此BitSet對(duì)象
removeAllElement()方法分析
public synchronized void removeAllElements() { modCount++; // Let gc do its work for (int i = 0; i < elementCount; i++) elementData[i] = null; elementCount = 0; }
用于刪除Vector對(duì)象持有的所有元素對(duì)象
1、fail-fast機(jī)制保護(hù)
實(shí)例變量modCount增加1,表示Vector持有的元素發(fā)生變化
2、遍歷數(shù)組對(duì)象
將Vector對(duì)象持有的數(shù)組對(duì)象elementData中實(shí)際保存元素對(duì)象引用的所有位置,全部賦值為null,當(dāng)對(duì)象從GC Roots處不可達(dá)時(shí),垃圾收集器會(huì)回收對(duì)象占用的內(nèi)存空間
3、元素總數(shù)標(biāo)記為0
Vector對(duì)象持有的elementCount標(biāo)記為0,說明Vector對(duì)象不再持有任何元素
removeAll(Collection)方法分析
public synchronized boolean removeAll(Collection<?> c) { return super.removeAll(c); }
用于刪除多個(gè)元素的方法,只有與傳入的Collection對(duì)象中持有的元素匹配的元素會(huì)被刪除
1、直接調(diào)用父類的removeAll()方法,并將傳入的Collection對(duì)象傳入進(jìn)去
2、向調(diào)用者返回刪除元素的結(jié)果
父類中的removeAll(Collection)方法分析
public boolean removeAll(Collection<?> c) { Objects.requireNonNull(c); boolean modified = false; Iterator<?> it = iterator(); while (it.hasNext()) { if (c.contains(it.next())) { it.remove(); modified = true; } } return modified; }
位于父類AbstractCollection中,用于刪除與傳入?yún)?shù)Collection對(duì)象中匹配的所有元素
1、檢查傳入?yún)?shù)Collection對(duì)象
2、定義局部變量,表示是否修改,默認(rèn)值false
3、調(diào)用iterator()方法獲取迭代器對(duì)象,并由局部變量it負(fù)責(zé)保存
此iterator()方法都是子類去實(shí)現(xiàn),Vector中也實(shí)現(xiàn)了該方法,此方法會(huì)返回一個(gè)迭代器對(duì)象
4、使用迭代器對(duì)象的方法進(jìn)行遍歷與刪除
hasNext()方法用于判斷是否有下一個(gè)元素,當(dāng)?shù)谝淮问褂脮r(shí),判斷的是第一個(gè)元素
next()方法可以獲取到一個(gè)元素,第一次使用時(shí),獲取到的是第一個(gè)元素
remove()方法可以刪除一個(gè)元素
每當(dāng)刪除一個(gè)元素(Vector中持有的元素與Collection中的某個(gè)元素相同),將是否修改的標(biāo)志位modified賦值為true
5、向調(diào)用者返回刪除結(jié)果
retainAll(Collection)方法分析
public synchronized boolean retainAll(Collection<?> c) { return super.retainAll(c); }
用于刪除除了傳入的Collection對(duì)象持有的元素之外的所有元素,求交集……
總結(jié)
1、即可以刪除一個(gè)元素、也可以刪除多個(gè)元素
2、fail-fast機(jī)制除了保護(hù)多線程下的使用,也防止在單線程下即遍歷、又刪除
3、為了規(guī)避一邊遍歷,一邊刪除的鍋,可以使用迭代器對(duì)象提供的一邊遍歷、一邊刪除的方法
以上就是基于java構(gòu)造方法Vector刪除元素源碼分析的詳細(xì)內(nèi)容,更多關(guān)于java構(gòu)造方法Vector的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)冪等性校驗(yàn)的示例代碼
我們?cè)谧鰓eb應(yīng)用的時(shí)候通常會(huì)遇到前端提交按鈕重復(fù)點(diǎn)擊的場(chǎng)景,在某些新增操作上就需要做冪等性限制來保證數(shù)據(jù)的可靠性,所以本文主要介紹了如何使用java?aop實(shí)現(xiàn)冪等性校驗(yàn),需要的可以參考下2024-02-02java 用redisTemplate 的 Operations存取list集合操作
這篇文章主要介紹了java 用redisTemplate 的 Operations存取list集合操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08實(shí)現(xiàn)一個(gè)基于Servlet的hello world程序詳解步驟
Java Servlet 是運(yùn)行在 Web 服務(wù)器或應(yīng)用服務(wù)器上的程序,它是作為來自 Web 瀏覽器或其他 HTTP 客戶端的請(qǐng)求和 HTTP 服務(wù)器上的數(shù)據(jù)庫(kù)或應(yīng)用程序之間的中間層2022-02-02Java中session存儲(chǔ)Users對(duì)象實(shí)現(xiàn)記住密碼
這篇文章主要介紹了Java中session存儲(chǔ)Users對(duì)象實(shí)現(xiàn)記住密碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Mybatis-plus自定義SQL注入器查詢@TableLogic邏輯刪除后的數(shù)據(jù)詳解
這篇文章主要給大家介紹了關(guān)于Mybatis-plus自定義SQL注入器查詢@TableLogic邏輯刪除后的數(shù)據(jù)的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03基于JavaMail的Java實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送功能
這篇文章主要為大家詳細(xì)介紹了基于JavaMail的Java實(shí)現(xiàn)簡(jiǎn)單郵件發(fā)送功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09JAVA實(shí)現(xiàn)簡(jiǎn)單停車場(chǎng)系統(tǒng)代碼
JAVA項(xiàng)目中正號(hào)需要一個(gè)停車收費(fèi)系統(tǒng),就整理出來java實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的停車收費(fèi)系統(tǒng)給大家分享一下,希望對(duì)大家有所幫助2017-04-04