Java 集合框架 ArrayList 原始碼剖析
總體介紹
ArrayList實現了List介面,是順序容器,即元素存放的資料與放進去的順序相同,允許放入null
元素,底層通過陣列實現。除該類未實現同步外,其餘跟Vector大致相同。每個ArrayList都有一個容量(capacity),表示底層陣列的實際大小,容器記憶體儲元素的個數不能多於當前容量。當向容器中新增元素時,如果容量不足,容器會自動增大底層陣列的大小。前面已經提過,Java泛型只是編譯器提供的語法糖,所以這裡的陣列是一個Object陣列,以便能夠容納任何型別的物件。
size(), isEmpty(), get(), set()方法均能在常數時間內完成,add()方法的時間開銷跟插入位置有關,addAll()方法的時間開銷跟新增元素的個數成正比。其餘方法大都是線性時間。
為追求效率,ArrayList沒有實現同步(synchronized),如果需要多個執行緒併發訪問,使用者可以手動同步,也可使用Vector替代。
方法剖析
set()
既然底層是一個陣列ArrayList的set()
方法也就變得非常簡單,直接對陣列的指定位置賦值即可。
public E set(int index, E element) { rangeCheck(index);//下標越界檢查 E oldValue = elementData(index); elementData[index] = element;//賦值到指定位置,複製的僅僅是引用 return oldValue; }
get()
get()
方法同樣很簡單,唯一要注意的是由於底層陣列是Object[],得到元素後需要進行型別轉換。
public E get(int index) { rangeCheck(index); return (E) elementData[index];//注意型別轉換 }
add()
跟C++ 的vector不同,ArrayList沒有bush_back()
方法,對應的方法是add(E e)
,ArrayList也沒有insert()
方法,對應的方法是add(int index, E e)
。這兩個方法都是向容器中新增新元素,這可能會導致capacity不足,因此在新增元素之前,都需要進行剩餘空間檢查,如果需要則自動擴容。擴容操作最終是通過grow()
方法完成的。
private void grow(int minCapacity) { int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//原來的3倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity);//擴充套件空間並複製 }
由於Java GC自動管理了記憶體,這裡也就不需要考慮源陣列釋放的問題。
空間的問題解決後,插入過程就顯得非常簡單。
add(int index, E e)
需要先對元素進行移動,然後完成插入操作,也就意味著該方法有著線性的時間複雜度。
addAll()
addAll()
方法能夠一次新增多個元素,根據位置不同也有兩個把本,一個是在末尾新增的addAll(Collection<? extends E> c)
方法,一個是從指定位置開始插入的addAll(int index, Collection<? extends E> c)
方法。跟add()
方法類似,在插入之前也需要進行空間檢查,如果需要則自動擴容;如果從指定位置插入,也會存在移動元素的情況。
addAll()
的時間複雜度不僅跟插入元素的多少有關,也跟插入的位置相關。
remove()
remove()
方法也有兩個版本,一個是remove(int index)
刪除指定位置的元素,另一個是remove(Object o)
刪除第一個滿足o.equals(elementData[index])
的元素。刪除操作是add()
操作的逆過程,需要將刪除點之後的元素向前移動一個位置。需要注意的是為了讓GC起作用,必須顯式的為最後一個位置賦null
值。
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); elementData[--size] = null; //清除該位置的引用,讓GC起作用 return oldValue; }
關於Java GC這裡需要特別說明一下,有了垃圾收集器並不意味著一定不會有記憶體洩漏。物件能否被GC的依據是是否還有引用指向它,上面程式碼中如果不手動賦null
值,除非對應的位置被其他元素覆蓋,否則原來的物件就一直不會被回收。
相關文章
- Java集合原始碼剖析——ArrayList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】Java集合框架Java原始碼框架
- Java 集合框架------ArrayList原始碼分析Java框架原始碼
- JAVA集合:ArrayList原始碼分析Java原始碼
- 【Java集合】ArrayList原始碼分析Java原始碼
- 集合框架原始碼學習之ArrayList框架原始碼
- Java集合之ArrayList原始碼解析Java原始碼
- java集合原始碼分析(三):ArrayListJava原始碼
- Java集合框架(一)-ArrayListJava框架
- Java集合原始碼學習(2)ArrayListJava原始碼
- JAVA ArrayList集合底層原始碼分析Java原始碼
- 死磕 java集合之ArrayList原始碼分析Java原始碼
- Java集合-ArrayList原始碼解析-JDK1.8Java原始碼JDK
- 集合-ArrayList 原始碼解析原始碼
- Java類集框架 —— ArrayList原始碼分析Java框架原始碼
- Java 集合 ArrayList 原始碼分析(帶著問題看原始碼)Java原始碼
- 集合原始碼分析[3]-ArrayList 原始碼分析原始碼
- ArrayList原始碼剖析與程式碼實測原始碼
- Java容器類框架分析(1)ArrayList原始碼分析Java框架原始碼
- JAVA集合-ArrayListJava
- Java集合——ArrayListJava
- 集合框架2- ArrayList框架
- Java——ArrayList原始碼解析Java原始碼
- 搞懂 Java ArrayList 原始碼Java原始碼
- ArrayList 從原始碼角度剖析底層原理原始碼
- Java 集合之ArrayListJava
- Java集合之ArrayListJava
- 【Java集合】2 ArrayListJava
- Java集合(一) —— ArrayListJava
- 純手寫Arraylist集合框架框架
- 還在深入瞭解集合框架(ArrayList、LinkedList)原始碼?先看看這篇文章吧框架原始碼
- 【java】【集合】去除ArrayList中的元素、ArrayList巢狀ArrayListJava巢狀
- Java容器原始碼學習--ArrayList原始碼分析Java原始碼
- Java LinkedList 原始碼剖析Java原始碼
- java基礎:ArrayList — 原始碼分析Java原始碼
- Java集合 ArrayList原理及使用Java
- Java Collection介面 ArrayList集合(容器)Java
- Java集合類原始碼Java原始碼
- Java 8 ArrayList 原始碼簡單分析Java原始碼