ArrayList源碼解析
主要方法
刪除元素
1
public E remove(int index) {
//檢查下標是否合法
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
//解釋在上一篇文章中
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
2
public boolean remove(Object o) {
//for循環遍歷去刪除指定元素,相同元素刪除下標小的
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
3從該列表中移除包含在指定集合中的所有元素。
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, false);
4僅保留包含在指定集合中的此列表中的元素。換句話說,從該列表中移除所有未包含在指定集合中的元素。
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
return batchRemove(c, true);
}
5removeAll和retainAll區別在於batchRemove(a,b)的第二個參數
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
/* 如果complement爲false,將c中不包含的ArrayList的元素放在一個elementData[]數組中,完成刪除;如果complement爲true,反之。
*/
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];
} finally {
// 保存和收集的行爲兼容性,
/ /即使C. contains()拋出。
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
遍歷ArrayList的方法
for(Object o:list)
for(int i=0;i<=list.size();i++)
Iterator<String> i = list.iterator();while(i.hasNext())
問題:遍歷的時候去刪除元素,會出現什麼問題?
List<String> list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add(1, "6");
list.remove("11");
for(String i:list){
list.remove(i);
}
for(int i=0;i<=list.size();i++){
list.remove(i);
}
System.out.println(list.isEmpty());
Iterator<String> i = list.iterator();
while(i.hasNext()){
i.remove();
}
foreach會拋ConcurrentModificationException
for循環卻是刪除不完元素
使用iterator則沒有問題
foreach在循環遍歷時,底層也是 private class Itr implements Iterator這個內部類的方法。
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
//foreach循環時,刪除完元素的下一次遍歷在這裏拋異常是因爲modCount和expectedModCount 的大小不一樣了,(內部類無法同步外部變量)
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];
}
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();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
for循環在刪除時,size的大小隨着每次刪除完,大小在變化,所以沒法刪除完全。
有問題歡迎提出。