資料結構(一)ArrayList原始碼分析
阿新 • • 發佈:2018-11-21
一、相關特性:
1、關係圖:
2、特點:
* 元素所佔儲存空間是連續的
* 基於陣列實現,容量可自增
* 可通過角標獲取指定位置的元素
* 查詢快(基於陣列索引),增刪慢(涉及到陣列複製、移動和擴容)
二、建構函式和變數:
1、變數:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
//首次預設擴充套件的值
private static final int DEFAULT_CAPACITY = 10;
//空陣列
private static final Object[] EMPTY_ELEMENTDATA = {};
//預設的elementData
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//元素的儲存結構為陣列
transient Object[] elementData;
//陣列長度
private int size;
......
2、建構函式
(1)使用無參構造建立一個ArrayList,預設陣列為空{}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
(2)可通過構造指定陣列的大小
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0 ) {
//如果傳入0,陣列為空陣列
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
(3)可傳入一個集合
public ArrayList(Collection<? extends E> c) {
//轉為陣列,賦值給elementData
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//這個啥bug?
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 空陣列
this.elementData = EMPTY_ELEMENTDATA;
}
}
c.toArray might (incorrectly) not return Object[]:
List<String> dataList = new ArrayList<String>();
dataList.add("one");
dataList.add("two");
Object[] listToArray = dataList.toArray();
通過toArray轉為Object陣列(內部實現不同),但是listToArray不一定能放置Object物件,出現這種情況就通過Arrays.copyOf來建立一個Object陣列,就可以存放任意類似的元素了。
三、新增元素:
1、隊尾新增元素
* 進行資料長度判斷,不夠進行擴容
* 隊尾插入元素
public boolean add(E e) {
//(1)擴容
ensureCapacityInternal(size + 1); // Increments modCount!!
//(2)賦值
elementData[size++] = e;
return true;
}
(1)擴容
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//所需最小容量
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 需要擴容了
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//1.5倍擴容
int newCapacity = oldCapacity + (oldCapacity >> 1);
//如果還不滿足,直接擴容到minCapacity
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);
}
擴容機制:
* 建立一個空陣列elementData,第一次插入資料時擴容到10
* 如果elementData長度不夠就直接擴容1.5倍
* 如果還不夠,就使用需要的長度作為elementData的長度
2、指定位置新增元素
* 進行資料長度判斷,不夠進行擴容
* 進行陣列複製
* 插入元素
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//(1)確保陣列長度足夠
ensureCapacityInternal(size + 1); // Increments modCount!!
//(2)將資料向後移動一位
System.arraycopy(elementData, index, elementData, index + 1, size - index);
//(3)插入元素
elementData[index] = element;
size++;
}
(1)陣列擴容同上
(2)陣列複製
* @param src 原陣列
* @param srcPos 原陣列要複製的開始位置
* @param dat 目標陣列
* @param dstPos 目標陣列的開始位置
* @param length 要複製的長度
* /
public static native void arraycopy(Object src, int srcPos,
Object dst, int dstPos, int length);
四、刪除元素:
public E remove(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
//陣列前移
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//最後位置的元素置null
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
五、修改元素:
public E set(int index, E element) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
//獲取當前位置元素
E oldValue = (E) elementData[index];
//當前位置置為新元素
elementData[index] = element;
return oldValue;
}
六、獲取元素:
public E get(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
return (E) elementData[index];
}
根據索引獲取陣列