JDK版本:1.8
我們進入ArrayList類查看類結構如下:
類的結構已經明確舔哪,我們以下內容就分為兩個部分,介紹構造函數(shù)和方法
構造函數(shù)
我們先看這個空構造
List<String> list = new ArrayList<String>();
//定義一個空數(shù)組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//定義數(shù)組中的元素 transient 表明該變量不支持序列化
transient Object[] elementData;
/**
* Constructs an empty list with an initial capacity of ten.
上面的英文翻譯個人認為不對病蛉,上來的時候DEFAULTCAPACITY_EMPTY_ELEMENTDATA只是一個空數(shù)組店茶,并不涉及到數(shù)組有多大
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList內部是由數(shù)組實現(xiàn)歧焦,elementData這個object類型的數(shù)組即為其存儲的數(shù)據(jù)結構
再看這個有參構造
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);
}
}
傳入參數(shù)initialCapacity大于0時就將elementData初始化為一個initialCapacity大小的數(shù)組
傳入參數(shù)initialCapacity等于0時和無參時保持一致
傳入參數(shù)initialCapacity小于零時拋出IllegalArgumentException異常
構造函數(shù)先看到這里...比較簡單
常用方法
size()
//數(shù)組中包含的元素多少
private int size;
public int size() {
return size;
}
當然size的數(shù)量肯定是在add或者remove時動態(tài)修改的
add()
/**
* 向數(shù)組的末尾添加一個元素
*/
public boolean add(E e) {
//檢測是否需要并擴容 說白了就是添加一個元素之前 看看容量夠不夠
//添加新元素是比對容器是不是夠大 你看它用size+1 多線程就會出現(xiàn)問題
// size的值在其它線程中可變
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
//判斷元素是否是首次添加
/**
* 默認擴容大小.
*/
private static final int DEFAULT_CAPACITY = 10;
private void ensureCapacityInternal(int minCapacity) {
//判斷elementData 中是否包含數(shù)據(jù) 也意為是否為首次添加
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//首次初始化數(shù)組大小時缺脉,默認給10 找不到為啥要比一下 首次添加元素 minCapacity肯定為1
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//此處的minCapacity為目標容量
ensureExplicitCapacity(minCapacity);
}
首次添加元素嘛,首次的話也不會直接初始化容量為1的數(shù)組 而是直接來個大小為10的數(shù)組
//數(shù)組的修改次數(shù)
protected transient int modCount = 0;
//判斷容器本身容量還夠不夠
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
// 容器本身容量和目標容量做對比 判斷是否需要擴容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
目標容量和本身容量作比較劳秋,如果本身容量不夠了 就擴容
/**
* 擴容
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
// 本人容量 首次為0
int oldCapacity = elementData.length;
// 擴容原則是 老容量的一半 7的一半是3
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 擴容完后的值能不能夠用
if (newCapacity - minCapacity < 0)
// 不夠用 直接用目標容量
newCapacity = minCapacity;
//最后的容量是不是比 最大整形還大
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果太大最高也就給最大整型-8的值 適配其他虛擬機 為啥要-8 其他vm整型頭信息可能會有別的用
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
整個過程如下:
你想找一個盆兒盛水
你媽先不管你要多少水 先給你個盆兒 這個盆兒肯定是咱平時能盛水用的
你要往盆兒里加水
麻麻得看盆兒有沒有地兒裝仓手,如果不夠了就再找個比現(xiàn)在盆兒1.5倍的盆兒(如果還不夠就再找個肯定夠的盆兒)
看看是不是裝的水太多了胖齐,如果太多 最多給你一個缸
addAll()
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
//日常擴容 詳見上面
ensureCapacityInternal(size + numNew); // Increments modCount
//原數(shù)組 a,開始索引0,目標數(shù)組elementData嗽冒,開始位置size(本來就比索引多1),numNew全挪
System.arraycopy(a, 0, elementData, size, numNew);
//新老數(shù)組的合
size += numNew;
return numNew != 0;
}
兩個數(shù)組疊在一起的感覺
我有兩個棍插在洞里依次排列 | |
你有三個棍插在洞里依次排列 | | |
你想和我混成一排
System.arraycopy(a, 0, elementData, size, numNew);
a為你的那排棍
0為你想從你棍的第幾個開始 和我的混到一起
elementData為我那排棍
size 為接納你棍的起始位置
numNew為 為你預備出來幾個洞
remove()
//數(shù)組的修改次數(shù)
protected transient int modCount = 0;
public boolean remove(Object o) {
//判斷是否list.remove(null) 遍歷數(shù)組 尋找為null的值
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;
}
/*
* Private remove method that skips bounds checking and does not
* return the value removed.
*/
private void fastRemove(int index) {
//被修改的次數(shù)加1
modCount++;
//size -1 看成轉換為索引 總索引-被刪除的值所在的索引 為剩余元素條目數(shù)
int numMoved = size - index - 1;
//如果剩余條目數(shù)大于0 則證明刪完后需要挪后面剩下的元素
if (numMoved > 0)
//參數(shù)分別為:原數(shù)組呀伙、需要挪動的啟示位置、挪動后的數(shù)組添坊、需要挪到的位置区匠、挪幾個
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//挪完后 少了個元素 最后一個肯定變成了空
elementData[--size] = null; // clear to let GC do its work
}
有五個孔, 圓木棍插在 孔中,依次排列了5個
| | | | |
此時想刪掉第二個,因此 找到第二個并拔出來帅腌,將第二個后面的木棍依次向前面挪
肯定剩了最后一個孔驰弄,拿土埋上
以上是數(shù)組的一些常用方法,其中的方方面面都是實際生活中的縮影
備注:ArrayList非線程安全 如果想線程安全 請使用Collections.synchronizedList(new ArrayLsit())包裝一下