ArrayList源碼相對簡單柬祠,這個數(shù)據(jù)結(jié)構(gòu)的底層就是一個動態(tài)數(shù)組缕题,在擴容時使用System類的copy方法朗儒。初始化容量為 0 在添加元素時會將數(shù)組擴容到10查坪,以后每一次擴容均擴容1.5倍肪跋。線程不安全的容器歧蒋,多線程環(huán)境不能使用。
這里說兩個需要注意的點州既,之前面試的時候遇到過谜洽。
1、ArrayList在執(zhí)行刪除操作之后吴叶,被刪除元素后面的元素都會向前移動一位阐虚,我在這里貼一下源碼:
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);
//將最后一個元素置為null
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
因為會自動向前進行移動所以在 for 循環(huán) 執(zhí)行刪除的時候,會出現(xiàn)意想不到的結(jié)果蚌卤。當然執(zhí)行 foreach 刪除也不行实束,會報錯:java.util.ConcurrentModificationException奥秆。這是因為在這里,foreach循環(huán)遍歷容器本質(zhì)上是使用迭代器進行遍歷的咸灿,會對修改次數(shù)modCount進行檢查构订,不允許集合進行更改操作,但是刪除的方法還是使用的ArrayList的remove()方法避矢,導(dǎo)致modCount修改悼瘾,最終拋出異常。源碼如下:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
如果想在遍歷時執(zhí)行刪除审胸,那就只有使用迭代器亥宿。使用迭代器遍歷刪除時,能夠避免ConcurrentModificationException歹嘹。這是因為:在ArrayList中箩绍,modCount是指集合的修改次數(shù),當進行add或者delete時尺上,modCount會+1材蛛;expectedModCount是指集合的迭代器的版本號,初始值是modCount怎抛,但是當集合進行add或者delete操作時卑吭,modCount會+1,而expectedModCount不會改變马绝,所以會拋出異常豆赏。但是迭代器remove操作時,會同步expectedModCount的值富稻,把modCount的值賦予expectedModCount掷邦。所以不會拋出異常。迭代器.remove的源碼如下:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
//對expectedModCount進行更新
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
2椭赋、Arrays工具類中的一個方法:asList(T... a) 它是將數(shù)組轉(zhuǎn)換成ArrayList的
public class Arrays {
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
}
小心抚岗,這里的ArrayList可不是 java.util;包中的類,這個是:Arrays工具類中的一個內(nèi)部類
public class Arrays {
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
}
}
可以看到它也繼承AbstractList也擁有ArrayList中的抽象方法哪怔,但是這個內(nèi)部類是沒有將這些方法實現(xiàn)的宣蔚,我們再看一下AbstractList中的add方法
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
一目了然,直接拋出異常认境。也就是我們在使用這個工具類轉(zhuǎn)換出來的ArrayList時是不能執(zhí)行添加和刪除操作的胚委。只能執(zhí)行修改操作
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
3、總結(jié):
1叉信、刪除時需要注意元素會自動向前移動亩冬;
2、foreach刪除是語法糖硼身,本質(zhì)上還是使用的迭代器硅急,會出現(xiàn)ConcurrentModificationException異常枢冤;
3、刪除時盡量使用迭代器铜秆。
我是巴哥淹真,我一定能進大廠!