arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?
作者:陌北有棵樹,玩Java,架構(gòu)師社區(qū)合伙人!
【一】關(guān)于擴(kuò)容
如果沒有指定初始容量,則設(shè)置為10
/**?*?Default?initial?capacity.
?*/
private?static?final?int?DEFAULT_CAPACITY?=?10;
ArrayList的擴(kuò)容比較簡單,容量擴(kuò)為之前的1.5倍
/**
?*?Increases?the?capacity?to?ensure?that?it?can?hold?at?least?the
?*?number?of?elements?specified?by?the?minimum?capacity?argument.
?*
?*?@param?minCapacity?the?desired?minimum?capacity
?*/
private?void?grow(int?minCapacity)?{
????//?overflow-conscious?code
????int?oldCapacity?=?elementData.length;
????int?newCapacity?=?oldCapacity?+?(oldCapacity?>>?1);
????if?(newCapacity?-?minCapacity?0)
????????newCapacity?=?minCapacity;
????if?(newCapacity?-?MAX_ARRAY_SIZE?>?0)
????????newCapacity?=?hugeCapacity(minCapacity);
????//?minCapacity?is?usually?close?to?size,?so?this?is?a?win:
????elementData?=?Arrays.copyOf(elementData,?newCapacity);
}
【二】關(guān)于拷貝
源碼中用到的數(shù)組復(fù)制的兩個方法分別是:System.arraycopy()和Arrays.copyOf()
一句話總結(jié)二者區(qū)別:Arrays.copyOf()可以看做是受限制的System.arraycopy()
Arrays.copyOf()是系統(tǒng)自己創(chuàng)建一個數(shù)組,再調(diào)用System.arraycopy()復(fù)制
public?static??T[]?copyOf(U[]?original,?int?newLength,?Class?extends?T[]>?newType)?{@SuppressWarnings("unchecked")????T[]?copy?=?((Object)newType?==?(Object)Object[].class)
??????????(T[])?new?Object[newLength]
????????:?(T[])?Array.newInstance(newType.getComponentType(),?newLength);
????System.arraycopy(original,?0,?copy,?0,
?????????????????????Math.min(original.length,?newLength));return?copy;
}
System.arraycopy()需要傳入一個目標(biāo)數(shù)組作為參數(shù),同時可以指定拷貝的起點(diǎn)和拷貝的長度
public?static?native?void?arraycopy(Object?src,??int??srcPos,????????????????????????????????????Object?dest,?int?destPos,int?length);
各個參數(shù)的含義:
src - 源數(shù)組。
srcPos - 源數(shù)組中的起始位置。
dest - 目標(biāo)數(shù)組。
destPos - 目標(biāo)數(shù)據(jù)中的起始位置。
length - 要復(fù)制的數(shù)組元素的數(shù)量。
同時要注意的是,上述兩個拷貝方法都是淺拷貝,關(guān)于深拷貝和淺拷貝,后續(xù)會做詳細(xì)說明。
【三】關(guān)于Fail-Fast
Fail-Fast是非線程安全的集合,實(shí)現(xiàn)的一種錯誤機(jī)制。但不能百分百得到保證,只是盡最大努力拋出ConcurrentModificationException。
什么時候產(chǎn)生Fail-Fast
ArrayList中如何實(shí)現(xiàn)Fail-Fast
兩個變量:modCount和expectedModCount
只要涉及到數(shù)組個數(shù)改變的方法,都會導(dǎo)致modCount的改變(add、remove、clear)
當(dāng)發(fā)現(xiàn)expectedModCount和modCount不一致,就會拋出ConcurrentModificationException
所以,Iterator在遍歷時,是不允許被迭代的對象被改變的
????if?(modCount?!=?expectedModCount)
????????throw?new?ConcurrentModificationException();
}
如何避免Fail-Fast:用CopyOnWriteArrayList代替ArrayList
【四】關(guān)于ArrayList中刪除元素
錯誤的刪除方式一:for循環(huán)遍歷刪除
public?void?testRemove()?{???List?integers?=?new?ArrayList<>(5);
???integers.add(1);
???integers.add(2);
???integers.add(2);
???integers.add(4);
???integers.add(5);for?(int?i?=?0;?i???????if?(integers.get(i)?%?2?==?0)?{
?????????integers.remove(i);
??????}
???}
???System.out.println(integers);
}
這段代碼的輸出是 [1,2,5]
因?yàn)樵趓emove方法執(zhí)行的時候,刪除第一個“2”,會更新后面的索引值,數(shù)組變?yōu)閇1,2,4,5],這樣會導(dǎo)致第二個“2”不會被刪除
錯誤的刪除方式二:使用Iterator遍歷,但仍用ArrayList的remove方法
public?void?testRemove(){???List?strings?=?new?ArrayList<>();
???strings.add("a");
???strings.add("b");
???strings.add("c");
???strings.add("d");
???Iterator?iterator?=?strings.iterator();while?(iterator.hasNext()){
??????String?next?=?iterator.next();
??????strings.remove(next);
???}
???System.out.println(strings);
}
會拋出ConcurrentModificationException,參見上述的Fail-Fast機(jī)制
正確的刪除方法:使用Iterator的remove方法
public?static?void?main(String[]?args)?{???List?intList?=?new?ArrayList();
???Collections.addAll(intList,?1,?2,?3,?5,?6);
???Iterator?it?=?intList.iterator();while(it.hasNext())?{
??????Integer?value?=?it.next();if(value?==?3?||?value?==?5)?{
?????????it.remove();
??????}
???}
???System.out.println(intList);
}
長按訂閱更多精彩▼
如有收獲,點(diǎn)個在看,誠摯感謝
總結(jié)
以上是生活随笔為你收集整理的arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rmse多少算效果好_关键词SEO优化带
- 下一篇: Linux ls常见的命令选项【转载】