摘要:說明是對中數(shù)組的擴(kuò)展,其底層還是使用數(shù)據(jù)實現(xiàn),支持自動擴(kuò)容,不是線程安全的類。其繼承,實現(xiàn)了各個接口,其中為支持隨機(jī)讀寫的標(biāo)記接口,在后續(xù)類的講解中會用到。加上主要是為了不能直接序列化,而是必須使用自帶的和方法,主要是為了節(jié)省空間。
1.說明
ArrayList是對java中數(shù)組的擴(kuò)展,其底層還是使用數(shù)據(jù)實現(xiàn),支持自動擴(kuò)容,不是線程安全的類。其繼承AbstractList,實現(xiàn)了List, RandomAccess, Cloneable,Serializable各個接口,其中RandomAccess為支持隨機(jī)讀寫的標(biāo)記接口,在后續(xù)Collections類的講解中會用到。
2.優(yōu)缺點ArrayList是一個支持自動擴(kuò)容的線性表,所以其與普通線性表的特點一樣,如下:
順序存儲,所以按照下標(biāo)讀取元素的時間復(fù)雜度為O(1)
在刪除元素時其后面的所有元素都得前移,新增元素時后面的所有元素都得后移
在存儲時就需要開辟一塊固定的存儲空間
3.重要變量//默認(rèn)的容量,當(dāng)構(gòu)造函數(shù)沒有傳入此參數(shù)時,會在加入第一個元素時將數(shù)組擴(kuò)容為此值 private static final int DEFAULT_CAPACITY = 10; //當(dāng)數(shù)組中元素為空時,會將數(shù)組初始化為此數(shù)組,代表空數(shù)組,這個空數(shù)組是在傳入 初始容量并且初始容量為0的情況下令數(shù)組等于這個 private static final Object[] EMPTY_ELEMENTDATA = {}; //與上一個變量的區(qū)別在于其是在于這個空數(shù)組是在使用無參構(gòu)造函數(shù)時創(chuàng)建 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //這個數(shù)組用于ArrayList存儲元素,ArrayList的容量就是數(shù)組的長度。加上transient主要是為了 不能直接序列化,而是必須使用自帶的writeObject和readObject方法,主要是為了節(jié)省空間。不私有 化主要是為了以后擴(kuò)展,防止以后嵌套等操作 transient Object[] elementData; // non-private to simplify nested class access //ArrayList的實際大小,即元素所占個數(shù) private int size;4.構(gòu)造方法
//傳入初始參數(shù)的構(gòu)造方法 public ArrayList(int initialCapacity) { //如果初始容量大于0,那么直接按照初始容量初始化數(shù)組, 如果初始容量等于0,等于EMPTY_ELEMENTDATA,上文 的常量,不過不會在添加第一個元素的時候令容量等于DEFAULT_CAPACITY 如果初始容量小于0,直接拋出異常 if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } //無參構(gòu)造函數(shù),直接令存儲數(shù)組等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA, 在添加第一個元素的時候令容量等于DEFAULT_CAPACITY public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } //通過一個集合類來構(gòu)造一個ArrayList public ArrayList(Collection extends E> c) { //獲取集合類的底層數(shù)組 elementData = c.toArray(); //判斷集合類的元素個數(shù)是否為0 if ((size = elementData.length) != 0) { //ps:c.toArray()可能返回的數(shù)組類型不為Object[]類型, 通過ArrayList的toArray一定是Object[]類型,但是Arrays.asList() 里轉(zhuǎn)化成其內(nèi)部自身的ArrayList,其內(nèi)部的ArrayList的toArray方法會 返回E[]這種泛型的對象,導(dǎo)致出現(xiàn)問題 //如果集合類的toArray方法返回的不為Object[]類型,使用Arrays.copyOf 將其遷移到一個新的Object[]數(shù)組中 if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { // 如果元素個數(shù)為0,那么直接將元素數(shù)組置為EMPTY_ELEMENTDATA空數(shù)組 this.elementData = EMPTY_ELEMENTDATA; } }5.基本方法
//增加一個新元素 public void add(int index, E element) { //檢驗index是否超出范圍 rangeCheckForAdd(index); //檢驗當(dāng)前容量是否足夠,如果不夠,進(jìn)行擴(kuò)容 ensureCapacityInternal(size + 1); //將index之后的元素都后移一個 System.arraycopy(elementData, index, elementData, index + 1, size - index); //將新增的元素填入 elementData[index] = element; //添加數(shù)組元素個數(shù) size++; } //檢驗index是否超出范圍 private void rangeCheckForAdd(int index) { //判斷index是否大于當(dāng)前長度或者小于0,如果不在數(shù)組范圍, 那么直接跑出數(shù)組超出范圍異常 if (index > size || index < 0) throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); } //確保內(nèi)部元素的容量足夠 private void ensureCapacityInternal(int minCapacity) { //對數(shù)組進(jìn)行擴(kuò)容 ensureExplicitCapacity(calculateCapacity(elementData, minCapacity)); } //用于判斷數(shù)組是不是DEFAULTCAPACITY_EMPTY_ELEMENTDATA,此處用==號進(jìn)行比較,是因為 只用于判斷是構(gòu)造函數(shù)時未傳初始容量,延遲到第一次添加新元素時進(jìn)行默認(rèn)初始容量的設(shè)置,然后 返回比較默認(rèn)容量與需要的最小容量的最大值,這里返回最大值是因為有可能一次添加多個元素, AddAll也會復(fù)用這個函數(shù) private static int calculateCapacity(Object[] elementData, int minCapacity) { if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) { return Math.max(DEFAULT_CAPACITY, minCapacity); } return minCapacity; } //對數(shù)組進(jìn)行擴(kuò)容 private void ensureExplicitCapacity(int minCapacity) { //修改次數(shù)+1 modCount++; // 如果需要的容量數(shù)大于當(dāng)前容量,進(jìn)行擴(kuò)容,否則,不在繼續(xù), 并且防止溢出,如果溢出,不進(jìn)行下列操作,直接會在后續(xù)數(shù)組 賦值中直接拋出越界異常,因為這個時候代表size已經(jīng)很大了 if (minCapacity - elementData.length > 0) grow(minCapacity); } //對數(shù)組進(jìn)行擴(kuò)容 private void grow(int minCapacity) { int oldCapacity = elementData.length; //令新的容量等于原容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); //如果新的容量小于當(dāng)前需要的的最小容量,那么新容量等于當(dāng)前需要的的最小容量 防止newCapacity溢出或者增加1.5倍還是小于minCapacity的情況 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; //如果新的容量比MAX_ARRAY_SIZE還大,MAX_ARRAY_SIZE為 Integer.MAX_VALUE - 8,那么對當(dāng)前需要的最小容量進(jìn)行擴(kuò)容 if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); //為數(shù)組開辟更大的空間 elementData = Arrays.copyOf(elementData, newCapacity); } //根據(jù)需要的容量進(jìn)行擴(kuò)容 private static int hugeCapacity(int minCapacity) { //如果minCapacity此時小于0,代表已經(jīng)溢出,其實此時已經(jīng)不大可能,因為在 ensureExplicitCapacity已經(jīng)有一層判斷了 if (minCapacity < 0) throw new OutOfMemoryError(); //如果minCapacity小于MAX_ARRAY_SIZE,那么直接等于MAX_ARRAY_SIZE, 否則直接等于Integer的最大值 return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; }
下面,來看看Api中的add,addAll等方法,其他類似方法不在贅述,get和set也不贅述,比較簡單
//與add方法不同的是,他是在這個索引處新增了一個集合的元素 public boolean addAll(int index, Collection extends E> c) { //檢驗index是否合法 rangeCheckForAdd(index); Object[] a = c.toArray(); int numNew = a.length; //size + numNew代表需要的最小容量 ensureCapacityInternal(size + numNew); //numMoved代表需要向后移動的元素個數(shù) int numMoved = size - index; if (numMoved > 0) System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //將集合c中的所有元素移動到elementData的index之后 System.arraycopy(a, 0, elementData, index, numNew); size += numNew; //如果集合c的長度不為0,返回true,否則返回false return numNew != 0; } //將elementData中的空元素去除,節(jié)省空間(去除不了中間的等于null這樣類型的元素) public void trimToSize() { modCount++; //如果當(dāng)前元素個數(shù)小于elementData的容量,當(dāng)size == 0時 將elementData賦值為EMPTY_ELEMENTDATA,否則,將elementData 容量減小到size大小 if (size < elementData.length) { elementData = (size == 0) ? EMPTY_ELEMENTDATA : Arrays.copyOf(elementData, size); } } //根據(jù)對應(yīng)元素計算出元素位置(遍歷為從前到后) public int indexOf(Object o) { //如果傳入元素為null,找到等于null的元素,否則,使用 equals遍歷 if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } //移除當(dāng)前元素 public E remove(int index) { rangeCheck(index); modCount++; //獲取當(dāng)前index在數(shù)組對應(yīng)元素 E oldValue = elementData(index); //獲取需要移動的元素個數(shù),即index之后的元素都需要向前移動,不包括index int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); //將最后一個元素置為空,其中的元素有g(shù)c自動回收 elementData[--size] = null; //返回被刪除的元素值 return oldValue; } //對對應(yīng)元素進(jìn)行移除,先遍歷查找,在進(jìn)行移除,值得一提的是, 此處的remove方法,使用的是fastRemove,與remove方法具體 少了rangeCheck方法和獲取oldValue,從而減少時間復(fù)雜度 public boolean remove(Object o) { 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; }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/77240.html
摘要:數(shù)組的大小會根據(jù)容量的增長而動態(tài)的增長,具體的增長方式請看這里構(gòu)造函數(shù)提供了三種方式的構(gòu)造器。這些元素按照該的迭代器返回的順序排列的。 原文地址 ArrayList ArrayList是List接口的 可變數(shù)組的實現(xiàn)。實現(xiàn)了所有可選列表操作,并允許包括 null 在內(nèi)的所有元素。除了實現(xiàn) List接口外,此類還提供一些方法來操作內(nèi)部用來存儲列表的數(shù)組的大小。ArrayList繼承自 A...
摘要:當(dāng)多個線程對同一個集合的內(nèi)容進(jìn)行操作時,就可能會產(chǎn)生事件。當(dāng)某一個線程遍歷的過程中,的內(nèi)容被另外一個線程所改變了就會拋出異常,產(chǎn)生事件。在線程在遍歷過程中的某一時刻,線程執(zhí)行了,并且線程刪除了中的節(jié)點。 概要 前面,我們已經(jīng)學(xué)習(xí)了ArrayList。接下來,我們以ArrayList為例,對Iterator的fail-fast機(jī)制進(jìn)行了解。 1 fail-fast簡介 fail-fast...
摘要:線程不安全底層數(shù)據(jù)結(jié)構(gòu)是鏈表。的默認(rèn)初始化容量是,每次擴(kuò)容時候增加原先容量的一半,也就是變?yōu)樵瓉淼谋秳h除元素時不會減少容量,若希望減少容量則調(diào)用它不是線程安全的。 前言 聲明,本文用得是jdk1.8 前一篇已經(jīng)講了Collection的總覽:Collection總覽,介紹了一些基礎(chǔ)知識。 現(xiàn)在這篇主要講List集合的三個子類: ArrayList 底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組。線程不安全 ...
摘要:我們來看相關(guān)源碼我們看到封裝的和操作其實就是對頭結(jié)點的操作。迭代器通過指針,能指向下一個節(jié)點,無需做額外的遍歷,速度非???。不同的遍歷性能差距極大,推薦使用迭代器進(jìn)行遍歷。LinkedList類介紹 上一篇文章我們介紹了JDK中ArrayList的實現(xiàn),ArrayList底層結(jié)構(gòu)是一個Object[]數(shù)組,通過拷貝,復(fù)制等一系列封裝的操作,將數(shù)組封裝為一個幾乎是無限的容器。今天我們來介紹JD...
閱讀 1118·2021-09-26 10:15
閱讀 2240·2021-09-24 10:37
閱讀 2703·2019-08-30 13:46
閱讀 2765·2019-08-30 11:16
閱讀 2551·2019-08-29 10:56
閱讀 2659·2019-08-26 12:24
閱讀 3551·2019-08-23 18:26
閱讀 2735·2019-08-23 15:43