Java集合刪除元素ArrayList為例子分析


AbstractCollection集合類中有一個remove方法,該方法為瞭適配多種不同的集合,允許刪除空的元素,看這部分代碼的時候產生瞭疑問,為什麼這裡直接用it.remove()就直接刪除瞭?


    public boolean remove(Object o) {
Iterator<E> it = iterator();
if (o==null) {
while (it.hasNext()) {
if (it.next()==null) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (o.equals(it.next())) {
it.remove();
return true;
}
}
}
return false;
}

接下來,拿ArrayList為例子,進行說明。其繼承結構如下圖所示。並且,ArrayList內部有其使用的Iterator的實現類。


編寫一段測試代碼:


AbstractCollection<String> list = new ArrayList<>();
list.add("a");
list.add(null);
list.add(null);

Iterator<String> iter = list.iterator();
while(iter.hasNext()) {
if(iter.next() == null) {
iter.remove();
}
}
System.out.println(list);

關鍵點還是在於iter.next() == null 這一行,next的源碼如下:


        public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}

cusor在這裡表示的是遍歷時的索引,在調用next方法的時候其實cusor已經指向瞭當前元素的下一個元素,而使用lasrRet來獲取當前的索引上的數據並將其返回。


而remove()方法中是通過lastRet的索引進行刪除的。


        public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();

try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}

借助上文中提到的測試實例,可以進行每一步的推算。

1. 調用next()方法,cursor指向0號元素,i被賦值為cursor的值,然後cursor被修改為i+1,指向瞭1號元素,也就是null所在的位置, lastRet被賦值為0。

2. 調用next()方法,cursor指向瞭1號元素,賦值給i,然後cursor又通過i+1遞增變為2,lastRet被賦值為1

3. 執行刪除,刪除該集合lastRet上所代表的元素。刪除完成後修改cursor指針同時使得expectedModCount和modCount保持一致避免fastfail。

0 個評論

要回覆文章請先登錄註冊