JDK1.8,代碼:java.util.ArrayList.java
ArrayList
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
ArrayList實現了List、RandomAccess接口。可以插入空數據,也支持隨機訪問。
/**
* 序列化的版本號
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默認初始容量10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 用於空實例的共享空數組實例
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 用於默認大小的空實例的共享空數組實例
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存儲ArrayList元素的數組緩衝區
*/
transient Object[] elementData;
/**
* ArrayList的大小
*/
private int size;
構造函數
/**
* 用初始容量作爲參數的構造方法
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
//初始容量大於0,實例化數組
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//初始容量等於0,賦予空數組
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 無參的構造方法
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* 構造一個包含指定元素的列表集合
* 按照集合返回它們的順序迭代器
*
* 要將其元素放入此列表的集合;如果指定的集合爲空,拋出NullPointerException
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray(); // c爲空會拋出NullPointerException
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 用空數組替換
this.elementData = EMPTY_ELEMENTDATA;
}
}
構造方法指定元素列表集合示例:
package com.container.arraylist;
import java.util.ArrayList;
/**
* @Classname ArrayListDemo
* @Description 構造方法指定元素列表集合示例
* @Date 2019/10/19 13:01
* @Created by xiangty
*/
public class ArrayListDemo {
public static void main(String[] args) {
ArrayList<A> arrayList = new ArrayList<A>();
A a = null;
for (int i = 0; i < 10; i++) {
a = new A();
a.setA("addValue" + i);
arrayList.add(a);
}
ArrayList arrayList2 = new ArrayList(arrayList);
// 打印arrayList2集合的值
print(arrayList2);
}
public static void demo1() {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
for (int i = 0; i < 10; i++) {
arrayList.add(i);
}
ArrayList arrayList2 = new ArrayList(arrayList);
// 打印arrayList2集合的值
print(arrayList2);
}
public static <E> void print(ArrayList<E> arrayList){
arrayList.forEach((a) -> System.out.println(a));
}
}
class A {
private String A;
public String getA() {
return A;
}
public void setA(String a) {
A = a;
}
@Override
public String toString() {
return "A{" +
"A='" + A + '\'' +
'}';
}
}
從上述的構造方法中可知,默認情況下elementData是一個大小爲0的空數組,當指定大小的時候,elementData的初始化大小變成了指定的初始化。
ArrayList擴容
ArrayList相當於動態數據,其中最重要的兩個屬性:elementData
數組和 size
大小。
add(E e)新增方法
/**
* 將指定的元素追加到此列表的末尾
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
首先進行擴容校驗
將插入的值放到尾部,並將 size + 1
add(int index, E element)指定位置添加
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//複製,向後移動
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
也是首先擴容校驗
接着對數據進行復制,目的是把 index 位置空出來放本次插入的數據,並將後面的數據向後移動一個位置
ensureCapacityInternal方法
/**
* 確保內部容量
*/
private void ensureCapacityInternal(int minCapacity) {
//先判斷數組是否爲空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果數組爲空,將DEFAULT_CAPACITY(爲10)和minCapacity中較大的一個賦值給minCapacity
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
a).當空列表add()第1個元素時,調試可知:原本minCapacity爲1,在Math.max()方法比較後,minCapacity爲10。
b).但當add()第2個元素時,數組非空,直接進入ensureExplicitCapacity(minCapacity)(此時minCapacity爲2)。
ensureExplicitCapacity方法
private void ensureExplicitCapacity(int minCapacity) {
//定義於ArrayList的父類AbstractList,用於存儲結構修改次數
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
//如果數組的長度(elementData.length)小於最小容量(minCapacity),就擴容
grow(minCapacity);
}
a).當要add第1個元素時,這時elementData.length(爲0,因爲此時還是空列表)是要比minCapacity(爲10)小的,會進入grow(minCapacity)方法(minCapacity爲10)
b).當add第2個元素時,調試可知:minCapacity爲2,此時elementData.length(即是容量)在添加第一個元素後擴容成10了,比minCapacity大,不會去執行grow方法 。數組容量仍爲10。
c).所以當添加第3、4···到第10個元素時,依然不會執行grow方法,數組容量都爲10。
d).直到添加第11個元素,minCapacity(爲11)比elementData.length(爲10)要大。進入grow方法進行擴容
grow方法進行擴容
/**
* 用來分配數組的size最大值
*/
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
/*
右移一位相當於原數除以2,位運算的計算方式相對除以計算更快
新容量擴大爲原來容量的1.5
*/
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
//從minCapacity和這個newCapacity中取較大值作爲擴容後的新數組長度(新容量)。
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//如果新容量大於數組的最大size,進入hugeCapacity方法
newCapacity = hugeCapacity(minCapacity);
//將原來數組的數據複製到新的數組中
elementData = Arrays.copyOf(elementData, newCapacity);
}
當add第1個元素時,oldCapacity爲0,經比較後第一個if判斷成立,newCapacity = minCapacity(爲10)。但是第二個if判斷不會成立,即newCapacity 不比 MAX_ARRAY_SIZE大,則不會進入hugeCapacity方法。數組容量爲10,add方法中return true,size增爲1
第3、4···到第10個元素邏輯同第1個
當add第11個元素時,newCapacity爲15,比minCapacity(爲11)大,第一個if判斷不成立。新容量沒有大於數組最大size,不會進入hugeCapacity方法。數組容量擴爲15,add方法中return true,size增爲11法最後一步,在確定好新數組的大小後,會調用Arrays.copyOf()方法,以適當長度(newCapacity)新建一個原數組的拷貝,並修改原數組,指向這個新建數組
grow()方法最後一步,在確定好新數組的大小後,會調用Arrays.copyOf()方法,以適當長度(newCapacity)新建一個原數組的拷貝,並修改原數組,指向這個新建數組。java垃圾回收機制會自動回收原數組
elementData = Arrays.copyOf(elementData, newCapacity);
hugeCapacity方法
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//對minCapacity和MAX_ARRAY_SIZE進行比較
//若minCapacity大,將Integer.MAX_VALUE作爲新數組的大小
//若MAX_ARRAY_SIZE大,將MAX_ARRAY_SIZE作爲新數組的大小
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
ensureCapacity方法
add方法添加大量數據的時候,爲減少分配次數和提高效率,推薦使用ensureCapacity方法
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}