ArrayList集合底層擴容原理
- 前言概述
- 核心代碼
- 擴容操作
第一章 前言概述
第01節 概述
底層說明
ArrayList是List的實作類,它的底層是用Object陣列存盤,執行緒不安全
后期應用
適合用于頻繁的查詢作業,因為底層是陣列,可以快速通過陣列下標進行查找
第02節 區別
| 區別方向 | ArrayList集合 | LinkedList集合 |
|---|---|---|
| 執行緒安全 | 不安全 | 不安全 |
| 底層原理 | Object型別陣列 | 雙向鏈表 |
| 隨機訪問 | 支持(實作 RandomAccess介面) | 不支持 |
| 記憶體占用 | ArrayList 浪費空間,底層是陣列,末尾預留一部分容量空間 | LinkedList占用空間比ArrayList多,存在頭尾地址值占用空間 |
小結
ArrayList 集合的特點:
1. 執行緒不安全
2. 底層資料結構是陣列(查詢快,增刪慢,支持快速隨機訪問)
3. 記憶體占用會存在部分浪費,末尾會預留一部分容量空間
第二章 核心代碼
第01節 成員變數
代碼
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
/**
* 默認初始容量大小, 默認初始化容量為10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 空陣列,當集合內容置空的時候,底層使用空陣列標記
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用于無引數構造方法,創建物件的時候,使用這個陣列定義,
* 相比上面的陣列 EMPTY_ELEMENTDATA 可以進行區分,知道在添加元素的程序當中,容量增加多少
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 保存ArrayList資料的陣列,這個陣列會不斷的改變,前面沒有被 final 修飾表示地址值會發生的變化
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* ArrayList 所包含的元素個數,也就是在 ArrayList 集合底層,通過 size()方法,獲取到的元素個數
*/
private int size;
}
補充
1. ArrayList 集合底層存在6個成員變數
還有一個 private static final long serialVersionUID = 8683452581122892189L;
序列化使用, 目前針對于當前的操作程序當中, 暫時不會使用得到,
2. ArrayList 集合當中核心的兩個成員變數
A. 底層維護陣列 transient Object[] elementData;
B. 存盤的元素個數 private int size;
第02節 構造方法
代碼
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
/**
* 構造一個初始長度為0的空陣列,
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 在構造方法當中,傳遞一個引數集合c,將集合 c 轉換成為新的串列
* elementData 當中的資料,就是新集合存放的資料
* c.toArray 就是將原始集合的資料取出
* 如果取出的集合長度不為零的情況下,則復制 引數集合c 到 elementData 當中
* 如果取出的集合長度為零的情況下,則賦值為空陣列 EMPTY_ELEMENTDATA
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
/**
* 指定引數的長度大小
* 如果初始化的長度大于0,則回傳新的陣列
* 如果初始化的長度等于0,則回傳默認的空陣列作為集合 this.elementData = EMPTY_ELEMENTDATA;
* 如果初始化的長度小于0,則出現非法引數例外
*/
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);
}
}
}
補充(一) 無參構造創建物件

補充(二)帶參構造創建物件,帶有int型別引數

補充(三)帶參構造創建物件,帶有 集合型別引數

第三章 擴容操作
第01節 擴容代碼
核心方法介紹
來自于 ArrayList 集合當中的方法:
1. public boolean add(E e){ ... }
2. private void add(E e, Object[] elementData, int s){ .... }
3. private Object[] grow()
4. private Object[] grow(int minCapacity)
來自于其他類當中的功能
1. Arrays.copyOf(elementData, newCapacity); 表示來自于 陣列工具類 Arrays 當中的 copyOf() 底層使用的是 System.arraycopy() 方法
2. Math.max(DEFAULT_CAPACITY, minCapacity) 表示來自于 數學工具類 Math 當中的 max() 方法,比較兩個資料最大值,取較大者,回傳
核心代碼解釋
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
/**
* 將指定的元素添加到此集合的末尾位置
*
* modCount 是來自于父類的 AbstractList 當中的成員變數
* add(e, elementData, size) 呼叫自己下面的多載方法
* return true 表示當前的方法,一定可以添加成功,因為List系列的集合添加資料都是允許成功的 true 如果是Set此方法回傳false
*/
public boolean add(E e) {
modCount++;
add(e, elementData, size);
return true;
}
/**
* 這個方法是私有方法,僅僅自己可以使用,不允許外界訪問得到,便于上面的 add() 方法多載呼叫的
* 引數1: 表示需要添加的元素資料 E e
* 引數2: 表示成員變數當中, 需要維護管理的底層陣列 Object[] elementData
* 引數3: 表示成員變數當中, size 容器 elementData 當中存放的真實有效的資料個數
* 方法里面的邏輯: 當size已經等于了內部容器 elementData 的最大長度,則準備進行擴容的操作,擴容使用 grow() 方法
* 無論上面是否進行了擴容的操作,這里都需要將添加的元素賦值到陣列當中,也就是 elementData[s] = e;
* 并且將當前成員變數的 size 在原始資料的基礎上面,增加1,表示添加了新的元素之后,長度變化了,增加了1
*/
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow();
elementData[s] = e;
size = s + 1;
}
/**
* 這個方法是私有方法,僅僅自己可以使用,不允許外界訪問得到,便于上面的 add() 方法呼叫的
* 方法的內部呼叫了 ArrayList 當中自己多載的方法 grow(size + 1) 同時傳入了引數,
* 這里引數的含義,表示的是 集合當中總長度 size + 1 表示在原始size基礎上增加1
* 方法的回傳值是一個新的陣列,也就是擴容之后的陣列
*/
private Object[] grow() {
return grow(size + 1);
}
/**
* 這個方法是私有方法,僅僅自己可以使用,不允許外界訪問得到,便于上面的 grow() 方法呼叫的
* 這里的引數 minCapacity ,就是上面傳入的引數 size + 1,也就是說最小容量 minCapacity = size + 1
* 方法體當中的執行邏輯:
* 1. 獲取到了底層維護陣列的長度 int oldCapacity = elementData.length; 這里就是舊容量 oldCapacity
* 2. 判斷舊容量 oldCapacity 是否小于0,也就是 else 的邏輯,
* 如果滿足 if 當中的邏輯, 則表示 舊陣列當中存在資料,并且 舊陣列并不是 默認容量的空陣列地址值
* 說明: 擴容過的就不會是之前默認 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 的地址值
* 在這種情況下,就會得到 1.5被的陣列長度整數,傳遞給 Arrays.copyOf()方法進行擴容,得到新陣列回傳
* 如果滿足 else 當中的邏輯,則回傳 DEFAULT_CAPACITY 和 minCapacity 較大值,
* 說明: DEFAULT_CAPACITY 值表示的是成員變數,默認為 10
* 說明: minCapacity 在低于10的時候,表示的會是擴容添加的長度1,2,3..9.10.11..
*/
private Object[] grow(int minCapacity) {
int oldCapacity = elementData.length;
if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
int newCapacity = ArraysSupport.newLength(oldCapacity,
minCapacity - oldCapacity, /* minimum growth */
oldCapacity >> 1 /* preferred growth */);
return elementData = Arrays.copyOf(elementData, newCapacity);
} else {
return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
}
}
}
第02節 動態程序說明

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/275781.html
標籤:java
