arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?
作者:陌北有棵樹,玩Java,架構師社區合伙人!
【一】關于擴容
如果沒有指定初始容量,則設置為10
/**?*?Default?initial?capacity.
?*/
private?static?final?int?DEFAULT_CAPACITY?=?10;
ArrayList的擴容比較簡單,容量擴為之前的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);
}
【二】關于拷貝
源碼中用到的數組復制的兩個方法分別是:System.arraycopy()和Arrays.copyOf()
一句話總結二者區別:Arrays.copyOf()可以看做是受限制的System.arraycopy()
Arrays.copyOf()是系統自己創建一個數組,再調用System.arraycopy()復制
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()需要傳入一個目標數組作為參數,同時可以指定拷貝的起點和拷貝的長度
public?static?native?void?arraycopy(Object?src,??int??srcPos,????????????????????????????????????Object?dest,?int?destPos,int?length);
各個參數的含義:
src - 源數組。
srcPos - 源數組中的起始位置。
dest - 目標數組。
destPos - 目標數據中的起始位置。
length - 要復制的數組元素的數量。
同時要注意的是,上述兩個拷貝方法都是淺拷貝,關于深拷貝和淺拷貝,后續會做詳細說明。
【三】關于Fail-Fast
Fail-Fast是非線程安全的集合,實現的一種錯誤機制。但不能百分百得到保證,只是盡最大努力拋出ConcurrentModificationException。
什么時候產生Fail-Fast
ArrayList中如何實現Fail-Fast
兩個變量:modCount和expectedModCount
只要涉及到數組個數改變的方法,都會導致modCount的改變(add、remove、clear)
當發現expectedModCount和modCount不一致,就會拋出ConcurrentModificationException
所以,Iterator在遍歷時,是不允許被迭代的對象被改變的
????if?(modCount?!=?expectedModCount)
????????throw?new?ConcurrentModificationException();
}
如何避免Fail-Fast:用CopyOnWriteArrayList代替ArrayList
【四】關于ArrayList中刪除元素
錯誤的刪除方式一:for循環遍歷刪除
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]
因為在remove方法執行的時候,刪除第一個“2”,會更新后面的索引值,數組變為[1,2,4,5],這樣會導致第二個“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機制
正確的刪除方法:使用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);
}
長按訂閱更多精彩▼
如有收獲,點個在看,誠摯感謝
總結
以上是生活随笔為你收集整理的arraylist 的扩容机制_每天都用ArrayList,你读过它的源码么?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: rmse多少算效果好_关键词SEO优化带
- 下一篇: Linux ls常见的命令选项【转载】