基于java構造方法Vector刪除元素源碼分析
(注意:本文基于JDK1.8)


![]()
前言
包括迭代器中的remove()方法,以及刪除單個元素、刪除多個元素、刪除所有元素、刪除不包含的所有元素的方法,Vector中共計10個對外的API可以用于刪除元素,今天一起分析每一個刪除元素的方法是如何實現(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;
}
用于刪除指定下標單個元素的方法,傳入的參數(shù)index表示元素的下標,第一個元素的下標是0,這個基礎知識點不要忘記哦
1、為fail-fast機制保駕護航
modCount是Vector對象持有的一個int變量,它本身位于Vector的父類AbstractList中,此處增加1,表示Vector的元素狀態(tài)發(fā)生改變,迭代器那里會使用fail-fast,防止多線程下即遍歷又刪除,也防止單線程下,一邊遍歷元素、一邊刪除元素
2、檢查下標是否存在元素
檢查傳入的下標index是否存在元素,當index與elementCount相等或者大于elementCount,此處的index并沒有元素,所以不能刪除沒有元素的位置,此處作者拋出ArrayIndexOutOfBoundsException對象,為此告知調(diào)用者,你傳入的下標根本沒有元素,怎么刪除呢?
3、保存刪除的元素到局部變量
調(diào)用elementData元素,并傳入下標index,獲得指定下標處的元素,并由局部變量oldValue負責保存
4、計算需要挪動元素的數(shù)量
使用表示元素總數(shù)的elementCount減去index、減去1,得到需要挪動元素的數(shù)量并存儲到局部變量numMoved
5、挪動元素
如果需要挪動元素,就將index下標后面的所有元素向前挪動(復制)
6、減少元素總數(shù)值
先將元素總數(shù)elementCount減去1
7、將持有元素的引用,賦值為null
將Vector對象持有的數(shù)組elementData對象的指定下標處,賦值為null,GC會刪除沒有Root結點對象連接的對象
8、向調(diào)用者返回刪除后的元素
return會返回此時被刪除的元素對象
remove(Object)方法分析
public boolean remove(Object o) {
return removeElement(o);
}
用于將第一個匹配的元素對象刪除的方法,傳入的參數(shù)為元素對象,此方法并沒有使用synchronized修飾,那么它如何保證線程安全的刪除元素呢?往下看……
1、實際調(diào)用removeElement()方法
2、向調(diào)用者返回刪除結果
removeElement(Object)方法分析
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
用于刪除元素的方法,使用synchronized修飾,同一時刻只有獲得對象鎖的線程可以執(zhí)行該方法,未獲得對象鎖的線程,將被阻塞在方法的入口處,傳入的1個參數(shù)表示元素對象
1、fail-fast機制保護
modCount增加1,表示Vector持有的元素發(fā)生改變
2、獲取元素對象在數(shù)組中的下標
調(diào)用index()方法,同時會將元素對象ob傳入進去,返回值則由局部變量i負責存儲,它存儲的是元素在數(shù)組中下標
3、元素存在,則繼續(xù)執(zhí)行刪除工作
當局部變量i的值大于等于0,說明元素存儲在數(shù)組中(Vector對象持有一個數(shù)組對象,用于保存元素的引用),通過調(diào)用removeElement()方法完成刪除工作,最后向調(diào)用者返回true,表示刪除元素成功
4、當元素不存在時,向調(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 */
}
用于刪除指定下標的元素,使用synchronized修飾,同一時刻只有1個線程可以執(zhí)行該方法,其它未獲得對象鎖的線程將被阻塞在入口處,傳入的1個參數(shù)index表示元素的下標
1、fail-fast機制
modCount增加1,表示Vector保存的元素發(fā)生改變
2、檢查下標是否合理
當傳入的下標index大于等于Vector對象持有的elementCount值時,拋出ArrayIndexOutOfBoundsException,告知調(diào)用者,index >= xx值
當傳入的下標index小于0時,同樣拋出ArrayIndexOutOfBoundsException對象,此時只告知index值是多少
只有下標0至elementCount - 1的范圍內(nèi),才有元素,所以作者的保護相當?shù)暮侠?/p>
3、計算需要移動元素的數(shù)量
比如一共保存了5個元素(elementCount)、需要刪除下標為3的元素,下標為3的元素是第4個元素,后續(xù)需要挪動的元素數(shù)量為1,所以
公式為:remove_num = elementCount - index - 1,我們再套進來公式里:remove_num = 5 - 3 - 1
4、開始挪動元素
挪動元素,而采用的是復制元素,system類的靜態(tài)方法arrycopy即可做到,它接受5個參數(shù)
第一個參數(shù):表示需要從哪個數(shù)組對象中復制元素(源頭)
第二個參數(shù):表示需要從數(shù)組對象的哪個下標處,開始復制
第三個參數(shù):表示需要粘貼到哪個數(shù)組對象中(目標)
第四個參數(shù):表示需要粘貼到數(shù)組對象的起始下標
第五個參數(shù):表示共計復制幾個元素
5、記錄的元素總數(shù)減去1
elementCount減少1
6、將剩下的數(shù)組中,多余的引用,刪除掉
因為每個元素都向前復制了一位,所以此時的elementCount指向的下標處,還存著對象的引用,這會造成對象無法被GC回收,賦值為null,由GC回收對象占用的內(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;
}
實現(xiàn)Collection接口的方法,用于根據(jù)指定條件刪除元素的方法,同樣由synchronized修飾,同一時刻只有獲取到當前對象鎖的線程可以調(diào)用此方法,其它線程如果也調(diào)用此方法,會被阻塞在方法的入口處
1、檢查傳入的Predicate對象
確保Predicate對象必須傳入,此處使用Objects的靜態(tài)方法requireNonNull()檢查
2、創(chuàng)建用于記錄刪除數(shù)量的局部變量
removeCount,默認值為0
3、臨時存儲當前Vector對象持有的元素總數(shù)
創(chuàng)建一個局部變量size用于存儲當前元素總數(shù)elementCount
4、創(chuàng)建BitSet對象
利用Vector對象持有的元素總數(shù)size,用于創(chuàng)建一個BitSet對象,局部變量removeSet臨時指向該此BitSet對象
removeAllElement()方法分析
public synchronized void removeAllElements() {
modCount++;
// Let gc do its work
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
elementCount = 0;
}
用于刪除Vector對象持有的所有元素對象
1、fail-fast機制保護
實例變量modCount增加1,表示Vector持有的元素發(fā)生變化
2、遍歷數(shù)組對象
將Vector對象持有的數(shù)組對象elementData中實際保存元素對象引用的所有位置,全部賦值為null,當對象從GC Roots處不可達時,垃圾收集器會回收對象占用的內(nèi)存空間
3、元素總數(shù)標記為0
Vector對象持有的elementCount標記為0,說明Vector對象不再持有任何元素
removeAll(Collection)方法分析
public synchronized boolean removeAll(Collection<?> c) {
return super.removeAll(c);
}
用于刪除多個元素的方法,只有與傳入的Collection對象中持有的元素匹配的元素會被刪除
1、直接調(diào)用父類的removeAll()方法,并將傳入的Collection對象傳入進去
2、向調(diào)用者返回刪除元素的結果
父類中的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對象中匹配的所有元素
1、檢查傳入?yún)?shù)Collection對象
2、定義局部變量,表示是否修改,默認值false
3、調(diào)用iterator()方法獲取迭代器對象,并由局部變量it負責保存
此iterator()方法都是子類去實現(xiàn),Vector中也實現(xiàn)了該方法,此方法會返回一個迭代器對象
4、使用迭代器對象的方法進行遍歷與刪除
hasNext()方法用于判斷是否有下一個元素,當?shù)谝淮问褂脮r,判斷的是第一個元素
next()方法可以獲取到一個元素,第一次使用時,獲取到的是第一個元素
remove()方法可以刪除一個元素
每當刪除一個元素(Vector中持有的元素與Collection中的某個元素相同),將是否修改的標志位modified賦值為true
5、向調(diào)用者返回刪除結果
retainAll(Collection)方法分析
public synchronized boolean retainAll(Collection<?> c) {
return super.retainAll(c);
}
用于刪除除了傳入的Collection對象持有的元素之外的所有元素,求交集……
總結
1、即可以刪除一個元素、也可以刪除多個元素
2、fail-fast機制除了保護多線程下的使用,也防止在單線程下即遍歷、又刪除
3、為了規(guī)避一邊遍歷,一邊刪除的鍋,可以使用迭代器對象提供的一邊遍歷、一邊刪除的方法
以上就是基于java構造方法Vector刪除元素源碼分析的詳細內(nèi)容,更多關于java構造方法Vector的資料請關注腳本之家其它相關文章!

