arraylist能否接收强转类型_ArrayList 源码解析
點(diǎn)擊上方"IT牧場(chǎng)",選擇"設(shè)為星標(biāo)"
技術(shù)干貨每日送達(dá)!
前言
JDK源碼解析系列文章,都是基于JDK8分析的,雖然JDK14已經(jīng)出來(lái),但是JDK8我還不會(huì),我…
類圖
實(shí)現(xiàn)了RandomAccess接口,可以隨機(jī)訪問(wèn)
實(shí)現(xiàn)了Cloneable接口,可以克隆
實(shí)現(xiàn)了Serializable接口,可以序列化、反序列化
實(shí)現(xiàn)了List接口,是List的實(shí)現(xiàn)類之一
實(shí)現(xiàn)了Collection接口,是Java Collections Framework成員之一
實(shí)現(xiàn)了Iterable接口,可以使用for-each迭代
屬性
//?序列化版本UIDprivate?static?final?long
????????serialVersionUID?=?8683452581122892189L;
/**
?*?默認(rèn)的初始容量
?*/
private?static?final?int
????????DEFAULT_CAPACITY?=?10;
/**
?*?用于空實(shí)例的共享空數(shù)組實(shí)例
?*?new?ArrayList(0);
?*/
private?static?final?Object[]
????????EMPTY_ELEMENTDATA?=?{};
/**
?*?用于提供默認(rèn)大小的實(shí)例的共享空數(shù)組實(shí)例
?*?new?ArrayList();
?*/
private?static?final?Object[]
????????DEFAULTCAPACITY_EMPTY_ELEMENTDATA?=?{};
/**
?*?存儲(chǔ)ArrayList元素的數(shù)組緩沖區(qū)
?*?ArrayList的容量,是數(shù)組的長(zhǎng)度
?*?
?*?non-private?to?simplify?nested?class?access
?*/
transient?Object[]?elementData;
/**
?*?ArrayList中元素的數(shù)量
?*/
private?int?size;
小朋友,你四否有很多問(wèn)號(hào)?
為什么空實(shí)例默認(rèn)數(shù)組有的時(shí)候是EMPTY_ELEMENTDATA,而又有的時(shí)候是DEFAULTCAPACITY_EMPTY_ELEMENTDATA
為什么elementData要被transient修飾
為什么elementData沒有被private修飾?難道正如注釋所寫的non-private to simplify nested class access
帶著問(wèn)題,我們繼續(xù)往下看。
構(gòu)造方法
帶初始容量的構(gòu)造方法
/**?*?帶一個(gè)初始容量參數(shù)的構(gòu)造方法
?*
?*?@param??initialCapacity??初始容量
?*?@throws??如果初始容量非法就拋出
?*??????????IllegalArgumentException
?*/
public?ArrayList(int?initialCapacity)?{
????if?(initialCapacity?>?0)?{
????????this.elementData?=
????????????????new?Object[initialCapacity];
????}?else?if?(initialCapacity?==?0)?{
????????this.elementData?=?EMPTY_ELEMENTDATA;
????}?else?{
????????throw?new?IllegalArgumentException(
????????????????"Illegal?Capacity:?"+?initialCapacity);
????}
}
如果initialCapacity ,就創(chuàng)建一個(gè)新的長(zhǎng)度是initialCapacity的數(shù)組
如果initialCapacity == 0,就使用EMPTY_ELEMENTDATA
其他情況,initialCapacity不合法,拋出異常
無(wú)參構(gòu)造方法
/**?*?無(wú)參構(gòu)造方法?將elementData?賦值為
?*???DEFAULTCAPACITY_EMPTY_ELEMENTDATA
?*/
public?ArrayList()?{
????this.elementData?=
????????????DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
帶一個(gè)集合參數(shù)的構(gòu)造方法
/**?*?帶一個(gè)集合參數(shù)的構(gòu)造方法
?*
?*?@param?c?集合,代表集合中的元素會(huì)被放到list中
?*?@throws?如果集合為空,拋出NullPointerException
?*/
public?ArrayList(Collection?extends?E>?c)?{
????elementData?=?c.toArray();
????//?如果?size?!=?0
????if?((size?=?elementData.length)?!=?0)?{
????????//?c.toArray?可能不正確的,不返回?Object[]
????????//?https://bugs.openjdk.java.net/browse/JDK-6260652
????????if?(elementData.getClass()?!=?Object[].class)
????????????elementData?=?Arrays.copyOf(
????????????????????elementData,?size,?Object[].class);
????}?else?{
????????//?size?==?0
????????//?將EMPTY_ELEMENTDATA?賦值給?elementData
????????this.elementData?=?EMPTY_ELEMENTDATA;
????}
}
使用將集合轉(zhuǎn)換為數(shù)組的方法
為了防止c.toArray()方法不正確的執(zhí)行,導(dǎo)致沒有返回Object[],特殊做了處理
如果數(shù)組大小等于0,則使用 EMPTY_ELEMENTDATA
那么問(wèn)題來(lái)了,什么情況下c.toArray()會(huì)不返回Object[]呢?
public?static?void?main(String[]?args)?{????List?list?=?new?ArrayList<>(Arrays.asList("list"));//?class?java.util.ArrayList
????System.out.println(list.getClass());
????Object[]?listArray?=?list.toArray();//?class?[Ljava.lang.Object;
????System.out.println(listArray.getClass());
????listArray[0]?=?new?Object();
????System.out.println();
????List?asList?=?Arrays.asList("asList");//?class?java.util.Arrays$ArrayList
????System.out.println(asList.getClass());
????Object[]?asListArray?=?asList.toArray();//?class?[Ljava.lang.String;
????System.out.println(asListArray.getClass());//?java.lang.ArrayStoreException
????asListArray[0]?=?new?Object();
}
我們通過(guò)這個(gè)例子可以看出來(lái),java.util.ArrayList.toArray()方法會(huì)返回Object[]沒有問(wèn)題。而java.util.Arrays的私有內(nèi)部類ArrayList的toArray()方法可能不返回Object[]。
為什么會(huì)這樣?
我們看ArrayList的toArray()方法源碼:
public?Object[]?toArray()?{????//?ArrayLisy中?elementData是這樣定義的
????//?transient?Object[]?elementData;
????return?Arrays.copyOf(elementData,?size);
}
使用了Arrays.copyOf()方法:
public?static??T[]?copyOf(T[]?original,?int?newLength)?{//?original.getClass()?是?class?[Ljava.lang.Objectreturn?(T[])?copyOf(original,?newLength,?original.getClass());}
copyOf()的具體實(shí)現(xiàn):
public?static??T[]?copyOf(U[]?original,?int?newLength,?Class?extends?T[]>?newType)?{@SuppressWarnings("unchecked")/**?????*?如果newType是Object[]?copy?數(shù)組?類型就是?Object?
?????*?否則就是?newType?類型
?????*/
????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;
}
我們知道ArrayList中elementData就是Object[]類型,所以ArrayList的toArray()方法必然會(huì)返回Object[]。
我們?cè)倏匆幌耲ava.util.Arrays的內(nèi)部ArrayList源碼(截取的部分源碼):
private?static?class?ArrayList<E>?extends?AbstractList<E>implements?RandomAccess,?java.io.Serializable?{????//?存儲(chǔ)元素的數(shù)組
????private?final?E[]?a;
????ArrayList(E[]?array)?{
????????//?直接把接收的數(shù)組?賦值?給?a
????????a?=?Objects.requireNonNull(array);
????}
????/**
?????*?obj?為空拋出異常
?????*?不為空?返回?obj
?????*/
????public?static??T?requireNonNull(T?obj)?{if?(obj?==?null)throw?new?NullPointerException();return?obj;
????}@Overridepublic?Object[]?toArray()?{//?返回?a?的克隆對(duì)象return?a.clone();
????}
}
這是Arrays.asList()方法源碼
public?static??List?asList(T...?a)?{return?new?ArrayList<>(a);}
不難看出來(lái)java.util.Arrays的內(nèi)部ArrayList的toArray()方法,是構(gòu)造方法接收什么類型的數(shù)組,就返回什么類型的數(shù)組。
所以,在我們上面的例子中,實(shí)際上返回的是String類型的數(shù)組,再將其中的元素賦值成Object類型的,自然報(bào)錯(cuò)。
我們還是繼續(xù)看ArrayList吧…
插入方法
在列表最后添加指定元素
/**?*?在列表最后添加指定元素
?*
?*?@param?e?要添加的指定元素
?*?@return?true
?*/
public?boolean?add(E?e)?{
????//?增加?modCount?!!
????ensureCapacityInternal(size?+?1);?
????elementData[size++]?=?e;
????return?true;
}
在父類AbstractList上,定義了modCount 屬性,用于記錄數(shù)組修改的次數(shù)。
在指定位置添加指定元素
/**?*?在指定位置添加指定元素
?*?如果指定位置已經(jīng)有元素,就將該元素和隨后的元素移動(dòng)到右面一位
?*
?*?@param?index?待插入元素的下標(biāo)
?*?@param?element?待插入的元素
?*?@throws?可能拋出?IndexOutOfBoundsException
?*/
public?void?add(int?index,?E?element)?{
????rangeCheckForAdd(index);
????//?增加?modCount?!!
????ensureCapacityInternal(size?+?1);
????System.arraycopy(elementData,?index,?elementData,?index?+?1,
?????????????????????size?-?index);
????elementData[index]?=?element;
????size++;
}
插入方法調(diào)用的其他私有方法
/**?*?計(jì)算容量
?*/
private?static?int?calculateCapacity(
????????Object[]?elementData,?int?minCapacity)?{
????if?(elementData?==
????????????DEFAULTCAPACITY_EMPTY_ELEMENTDATA)?{
????????return?Math.max(DEFAULT_CAPACITY,?minCapacity);
????}
????return?minCapacity;
}
private?void?ensureCapacityInternal(int?minCapacity)?{
????ensureExplicitCapacity(
????????????calculateCapacity(elementData,?minCapacity)
????);
}
private?void?ensureExplicitCapacity(int?minCapacity)?{
????modCount++;
????//?overflow-conscious?code
????if?(minCapacity?-?elementData.length?>?0)
????????grow(minCapacity);
}
擴(kuò)容方法
/**?*?數(shù)組可以分配的最大size
?*?一些虛擬機(jī)在數(shù)組中預(yù)留一些header?words
?*?如果嘗試分配更大的size,可能導(dǎo)致OutOfMemoryError
?*/
private?static?final?int?MAX_ARRAY_SIZE?=?Integer.MAX_VALUE?-?8;
/**
?*?增加容量,至少保證比minCapacity大
?*?@param?minCapacity?期望的最小容量
?*/
private?void?grow(int?minCapacity)?{
????//?有可能溢出的代碼
????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);
}
/**
?*?最大容量返回?Integer.MAX_VALUE
?*/
private?static?int?hugeCapacity(int?minCapacity)?{
????if?(minCapacity?0)?//?overflow
????????throw?new?OutOfMemoryError();
????return?(minCapacity?>?MAX_ARRAY_SIZE)??
????????Integer.MAX_VALUE?:
????????MAX_ARRAY_SIZE;
}
通常情況新容量是原來(lái)容量的1.5倍
如果原容量的1.5倍比minCapacity小,那么就擴(kuò)容到minCapacity
特殊情況擴(kuò)容到Integer.MAX_VALUE
看完構(gòu)造方法、添加方法、擴(kuò)容方法之后,上文第1個(gè)問(wèn)題終于有了答案。原來(lái),new ArrayList()會(huì)將elementData 賦值為 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,new ArrayList(0)會(huì)將elementData 賦值為 EMPTY_ELEMENTDATA,EMPTY_ELEMENTDATA添加元素會(huì)擴(kuò)容到容量為1,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA擴(kuò)容之后容量為10。
通過(guò)反射我們可以驗(yàn)證這一想法。如下:
public?static?void?main(String[]?args)?{????printDefaultCapacityList();
????printEmptyCapacityList();
}
public?static?void?printDefaultCapacityList()?{
????ArrayList?defaultCapacity?=?new?ArrayList();
????System.out.println(
????????????"default?初始化長(zhǎng)度:"?+?getCapacity(defaultCapacity));
????defaultCapacity.add(1);
????System.out.println(
????????????"default?add?之后?長(zhǎng)度:"?+?getCapacity(defaultCapacity));
}
public?static?void?printEmptyCapacityList()?{
????ArrayList?emptyCapacity?=?new?ArrayList(0);
????System.out.println(
????????????"empty?初始化長(zhǎng)度:"?+?getCapacity(emptyCapacity));
????emptyCapacity.add(1);
????System.out.println(
????????????"empty?add?之后?長(zhǎng)度:"?+?getCapacity(emptyCapacity));
}
public?static?int?getCapacity(ArrayList>?arrayList)?{
????Class?arrayListClass?=?ArrayList.class;try?{//?獲取?elementData?字段
????????Field?field?=?arrayListClass.getDeclaredField("elementData");//?開啟訪問(wèn)權(quán)限
????????field.setAccessible(true);//?把示例傳入get,獲取實(shí)例字段elementData的值
????????Object[]?objects?=?(Object[])?field.get(arrayList);//返回當(dāng)前ArrayList實(shí)例的容量值return?objects.length;
????}?catch?(Exception?e)?{
????????e.printStackTrace();return?-1;
????}
}
移除方法
移除指定下標(biāo)元素方法
/**?*?移除列表中指定下標(biāo)位置的元素
?*?將所有的后續(xù)元素,向左移動(dòng)
?*
?*?@param?要移除的指定下標(biāo)
?*?@return?返回被移除的元素
?*?@throws?下標(biāo)越界會(huì)拋出IndexOutOfBoundsException
?*/
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);
????//?將引用置空,讓GC回收
????elementData[--size]?=?null;
????return?oldValue;
}
移除指定元素方法
/**?*?移除第一個(gè)在列表中出現(xiàn)的指定元素
?*?如果存在,移除返回true
?*?否則,返回false
?*
?*?@param?o?指定元素
?*/
public?boolean?remove(Object?o)?{
????if?(o?==?null)?{
????????for?(int?index?=?0;?index?????????????if?(elementData[index]?==?null)?{
????????????????fastRemove(index);
????????????????return?true;
????????????}
????}?else?{
????????for?(int?index?=?0;?index?????????????if?(o.equals(elementData[index]))?{
????????????????fastRemove(index);
????????????????return?true;
????????????}
????}
????return?false;
}
移除方法名字、參數(shù)的個(gè)數(shù)都一樣,使用的時(shí)候要注意。
私有移除方法
/*?*?私有的?移除?方法?跳過(guò)邊界檢查且不返回移除的元素
?*/
private?void?fastRemove(int?index)?{
????modCount++;
????int?numMoved?=?size?-?index?-?1;
????if?(numMoved?>?0)
????????System.arraycopy(elementData,?index+1,?elementData,?index,
?????????????????????????numMoved);
????//?將引用置空,讓GC回收
????elementData[--size]?=?null;
}
查找方法
查找指定元素的所在位置
/**?*?返回指定元素第一次出現(xiàn)的下標(biāo)
?*?如果不存在該元素,返回?-1
?*?如果?o?==null?會(huì)特殊處理
?*/
public?int?indexOf(Object?o)?{
????if?(o?==?null)?{
????????for?(int?i?=?0;?i?????????????if?(elementData[i]==null)
????????????????return?i;
????}?else?{
????????for?(int?i?=?0;?i?????????????if?(o.equals(elementData[i]))
????????????????return?i;
????}
????return?-1;
}
查找指定位置的元素
/**?*?返回指定位置的元素
?*
?*?@param??index?指定元素的位置?
?*?@throws?index越界會(huì)拋出IndexOutOfBoundsException
?*/
public?E?get(int?index)?{
????rangeCheck(index);
????return?elementData(index);
}
該方法直接返回elementData數(shù)組指定下標(biāo)的元素,效率還是很高的。所以ArrayList,for循環(huán)遍歷效率也是很高的。
序列化方法
/**?*?將ArrayLisy實(shí)例的狀態(tài)保存到一個(gè)流里面
?*/
private?void?writeObject(java.io.ObjectOutputStream?s)throws?java.io.IOException{
????//?Write?out?element?count,?and?any?hidden?stuff
????int?expectedModCount?=?modCount;
????s.defaultWriteObject();
????//?Write?out?size?as?capacity?for?behavioural?compatibility?with?clone()
????s.writeInt(size);
????//?按照順序?qū)懭胨械脑?br />????for?(int?i=0;?i????????s.writeObject(elementData[i]);
????}
????if?(modCount?!=?expectedModCount)?{
????????throw?new?ConcurrentModificationException();
????}
}
反序列化方法
/**?*?根據(jù)一個(gè)流(參數(shù))重新生成一個(gè)ArrayList
?*/
private?void?readObject(java.io.ObjectInputStream?s)throws?java.io.IOException,?ClassNotFoundException?{
????elementData?=?EMPTY_ELEMENTDATA;
????//?Read?in?size,?and?any?hidden?stuff
????s.defaultReadObject();
????//?Read?in?capacity
????s.readInt();
????if?(size?>?0)?{
????????//?be?like?clone(),?allocate?array?based?upon?size?not?capacity
????????ensureCapacityInternal(size);
????????Object[]?a?=?elementData;
????????//?Read?in?all?elements?in?the?proper?order.
????????for?(int?i=0;?i????????????a[i]?=?s.readObject();
????????}
????}
}
看完序列化,反序列化方法,我們終于又能回答開篇的第二個(gè)問(wèn)題了。elementData之所以用transient修飾,是因?yàn)镴DK不想將整個(gè)elementData都序列化或者反序列化,而只是將size和實(shí)際存儲(chǔ)的元素序列化或反序列化,從而節(jié)省空間和時(shí)間。
創(chuàng)建子數(shù)組
public?List?subList(int?fromIndex,?int?toIndex)?{????subListRangeCheck(fromIndex,?toIndex,?size);
????return?new?SubList(this,?0,?fromIndex,?toIndex);
}
我們看一下簡(jiǎn)短版的SubList:
private?class?SubList?extends?AbstractList<E>?implements?RandomAccess?{????private?final?AbstractList?parent;private?final?int?parentOffset;private?final?int?offset;int?size;
????SubList(AbstractList?parent,int?offset,?int?fromIndex,?int?toIndex)?{this.parent?=?parent;this.parentOffset?=?fromIndex;this.offset?=?offset?+?fromIndex;this.size?=?toIndex?-?fromIndex;this.modCount?=?ArrayList.this.modCount;
????}public?E?set(int?index,?E?e)?{
????????rangeCheck(index);
????????checkForComodification();
????????E?oldValue?=?ArrayList.this.elementData(offset?+?index);
????????ArrayList.this.elementData[offset?+?index]?=?e;return?oldValue;
????}//?省略代碼...
}
SubList的set()方法,是直接修改ArrayList中elementData數(shù)組的,使用中應(yīng)該注意
SubList是沒有實(shí)現(xiàn)Serializable接口的,是不能序列化的
迭代器
創(chuàng)建迭代器方法
public?Iterator?iterator()?{????return?new?Itr();
}
Itr屬性
//?下一個(gè)要返回的元素的下標(biāo)int?cursor;
//?最后一個(gè)要返回元素的下標(biāo)?沒有元素返回?-1
int?lastRet?=?-1;
//?期望的?modCount
int?expectedModCount?=?modCount;
Itr的hasNext() 方法
public?boolean?hasNext()?{????return?cursor?!=?size;
}
Itr的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];
}
final?void?checkForComodification()?{
????if?(modCount?!=?expectedModCount)
????????throw?new?ConcurrentModificationException();
}
在迭代的時(shí)候,會(huì)校驗(yàn)modCount是否等于expectedModCount,不等于就會(huì)拋出著名的ConcurrentModificationException異常。什么時(shí)候會(huì)拋出ConcurrentModificationException?
public?static?void?main(String[]?args)?{????ArrayList?arrayList?=?new?ArrayList();
????for?(int?i?=?0;?i?10;?i++)?{
????????arrayList.add(i);
????}
????remove(arrayList);
????System.out.println(arrayList);
}
public?static?void?remove(ArrayList?list)?{
????Iterator?iterator?=?list.iterator();while?(iterator.hasNext())?{
????????Integer?number?=?iterator.next();if?(number?%?2?==?0)?{//?拋出ConcurrentModificationException異常
????????????list.remove(number);
????????}
????}
}
那怎么寫才能不拋出ConcurrentModificationException?很簡(jiǎn)單,將list.remove(number);換成iterator.remove();即可。why?請(qǐng)看Itr的remove()源碼…
Itr的remove()方法
public?void?remove()?{????if?(lastRet?0)
????????throw?new?IllegalStateException();
????checkForComodification();
????try?{
????????ArrayList.this.remove(lastRet);
????????cursor?=?lastRet;
????????lastRet?=?-1;
????????//?移除之后將modCount?重新賦值給?expectedModCount
????????expectedModCount?=?modCount;
????}?catch?(IndexOutOfBoundsException?ex)?{
????????throw?new?ConcurrentModificationException();
????}
}
原因就是因?yàn)镮tr的remove()方法,移除之后將modCount重新賦值給 expectedModCount。這就是源碼,不管單線程還是多線程,只要違反了規(guī)則,就會(huì)拋異常。
源碼看的差不多了,開篇的問(wèn)題卻還剩一個(gè)!到底為什么elementData沒有用private修飾呢?
我們知道的,private修飾的變量,內(nèi)部類也是可以訪問(wèn)到的。難道注釋中non-private to simplify nested class access的這句話有毛病?
當(dāng)我們看表面看不到什么東西的時(shí)候,不妨看一下底層。
測(cè)試類代碼:
一頓javac、javap之后(使用JDK8):
再一頓javac、javap之后(使用JDK11):
雖然字節(jié)碼指令我還看不太懂,但是我能品出來(lái),注釋是沒毛病的,private修飾的確會(huì)影響內(nèi)部類的訪問(wèn)。
ArrayList類注釋翻譯
類注釋還是要看的,能給我們一個(gè)整體的了解這個(gè)類。我將ArrayList的類注釋大概翻譯整理了一下:
ArrayList是實(shí)現(xiàn)List接口的可自動(dòng)擴(kuò)容的數(shù)組。實(shí)現(xiàn)了所有的List操作,允許所有的元素,包括null值。
ArrayList大致和Vector相同,除了ArrayList是非同步的。
size isEmpty get set iterator 和 listIterator 方法時(shí)間復(fù)雜度是O(1),常量時(shí)間。其他方法是O(n),線性時(shí)間。
每一個(gè)ArrayList實(shí)例都有一個(gè)capacity(容量)。capacity是用于存儲(chǔ)列表中元素的數(shù)組的大小。capacity至少和列表的大小一樣大。
如果多個(gè)線程同時(shí)訪問(wèn)ArrayList的實(shí)例,并且至少一個(gè)線程會(huì)修改,必須在外部保證ArrayList的同步。修改包括添加刪除擴(kuò)容等操作,僅僅設(shè)置值不包括。這種場(chǎng)景可以用其他的一些封裝好的同步的list。如果不存在這樣的Object,ArrayList應(yīng)該用Collections.synchronizedList包裝起來(lái)最好在創(chuàng)建的時(shí)候就包裝起來(lái),來(lái)保證同步訪問(wèn)。
iterator()和listIterator(int)方法是fail-fast的,如果在迭代器創(chuàng)建之后,列表進(jìn)行結(jié)構(gòu)化修改,迭代器會(huì)拋出ConcurrentModificationException。
面對(duì)并發(fā)修改,迭代器快速失敗、清理,而不是在未知的時(shí)間不確定的情況下冒險(xiǎn)。請(qǐng)注意,快速失敗行為不能被保證。通常來(lái)講,不能同步進(jìn)行的并發(fā)修改幾乎不可能做任何保證。因此,寫依賴這個(gè)異常的程序的代碼是錯(cuò)誤的,快速失敗行為應(yīng)該僅僅用于防止bug。
總結(jié)
ArrayList底層的數(shù)據(jù)結(jié)構(gòu)是數(shù)組
ArrayList可以自動(dòng)擴(kuò)容,不傳初始容量或者初始容量是0,都會(huì)初始化一個(gè)空數(shù)組,但是如果添加元素,會(huì)自動(dòng)進(jìn)行擴(kuò)容,所以,創(chuàng)建ArrayList的時(shí)候,給初始容量是必要的
Arrays.asList()方法返回的是的Arrays內(nèi)部的ArrayList,用的時(shí)候需要注意
subList()返回內(nèi)部類,不能序列化,和ArrayList共用同一個(gè)數(shù)組
迭代刪除要用,迭代器的remove方法,或者可以用倒序的for循環(huán)
ArrayList重寫了序列化、反序列化方法,避免序列化、反序列化全部數(shù)組,浪費(fèi)時(shí)間和空間
elementData不使用private修飾,可以簡(jiǎn)化內(nèi)部類的訪問(wèn)
源碼系列第一篇,一不小心就寫的有點(diǎn)長(zhǎng)。但是懵懂到深刻的過(guò)程還是挺耐人尋味的。文章中沒有展開的點(diǎn),或者你有什么其他好奇的地方,歡迎留言討論。我們下篇文章再見…
干貨分享
最近將個(gè)人學(xué)習(xí)筆記整理成冊(cè),使用PDF分享。關(guān)注我,回復(fù)如下代碼,即可獲得百度盤地址,無(wú)套路領(lǐng)取!
?001:《Java并發(fā)與高并發(fā)解決方案》學(xué)習(xí)筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學(xué)習(xí)筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)速成)》?007:全部?008:加技術(shù)討論群
近期熱文
?徹底解決 GitHub 拉取代碼網(wǎng)速慢的問(wèn)題?基于 SpringBoot2 和 Netty 實(shí)現(xiàn)一個(gè)簡(jiǎn)易的RPC通信框架?一本徹底搞懂MySQL索引優(yōu)化EXPLAIN百科全書?盤點(diǎn) 10 個(gè)代碼重構(gòu)的小技巧?性能測(cè)試如何定位瓶頸?偶發(fā)超時(shí)?看高手如何快速排查問(wèn)題?震精!Spring Boot內(nèi)存泄露,排查竟這么難!
想知道更多?長(zhǎng)按/掃碼關(guān)注我吧↓↓↓>>>技術(shù)討論群<<<喜歡就點(diǎn)個(gè)"在看"唄^_^
總結(jié)
以上是生活随笔為你收集整理的arraylist能否接收强转类型_ArrayList 源码解析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: html侧滑菜单mui,mui侧滑菜单点
- 下一篇: springboot公共模块打包_解决S