ArrayList源碼簡單淺析
ArrayList 應(yīng)該是開發(fā)中用的最多的集合對象了,ArrayList是可以動(dòng)態(tài)增長和縮減的索引序列,它是基于數(shù)組實(shí)現(xiàn)的List類。
一些定義
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;
//默認(rèn)容量大小
private static final int DEFAULT_CAPACITY = 10;
// 默認(rèn)空的數(shù)組
private static final Object[] EMPTY_ELEMENTDATA = {};
//默認(rèn)空容量的數(shù)組
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//維護(hù)的數(shù)組,用來存入元素
transient Object[] elementData;
// 實(shí)際元素個(gè)數(shù)
private int size;
構(gòu)造方法
//無參數(shù)的構(gòu)造方法 初始化數(shù)組為空
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
//帶容量參數(shù)的構(gòu)造方法
public ArrayList(int initialCapacity) {
//判斷容量是否大于0
if (initialCapacity > 0) {
//new 一個(gè)initialCapacity 大小的數(shù)組
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
//初始化為空數(shù)組
this.elementData = EMPTY_ELEMENTDATA;
} else {
//initialCapacity 小于0 拋出異常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
//帶集合的構(gòu)造方法
public ArrayList(Collection<? extends E> c) {
//將集合轉(zhuǎn)換為數(shù)組 并賦值給當(dāng)前的容器數(shù)組
elementData = c.toArray();
//判斷長度是不是為空
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
//這里判斷返回值是否為Object類不是就賦值復(fù)制
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array. 如果是Object就賦值為空數(shù)組
this.elementData = EMPTY_ELEMENTDATA;
}
}
c.toArray might (incorrectly) not return Object[] (see 6260652)
這里主要是list.toArray()實(shí)現(xiàn)方式不一樣,導(dǎo)致返回的數(shù)組真實(shí)類型不一樣
//java.util.Arrays$ArrayList
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
//java.util.ArrayList
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
add方法
public boolean add(E e) {
//操作次數(shù)+1
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
ensureCapacityInternal
private void ensureCapacityInternal(int minCapacity) {
//判斷當(dāng)前是不是空
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
//如果是就DEFAULT_CAPACITY =10 ,minCapacity=size+1第一次是1 取大值和所以第一次 minCapacity =10
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//第二次 elementData 不是空 minCapacity =size+1,
ensureExplicitCapacity(minCapacity);
}
ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
//修改次數(shù)+1
modCount++;
//第一次10 -10不會(huì)執(zhí)行
// overflow-conscious code
//第二次,elementData不是空的數(shù)組了
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
minCapacity如果大于了實(shí)際elementData的長度,那么就說明elementData數(shù)組的長度不夠用,不夠用那么就要增加elementData的length。這里有的同學(xué)就會(huì)模糊minCapacity到底是什么呢,這里給你們分析一下:
- 第一種情況:由于elementData初始化時(shí)是空的數(shù)組,那么第一次add的時(shí)候,minCapacity=size+1;也就minCapacity=1,在上一個(gè)方法(確定內(nèi)部容量ensureCapacityInternal)就會(huì)判斷出是空的數(shù)組,就會(huì)給
將minCapacity=10,到這一步為止,還沒有改變elementData的大小, - 第二種情況:elementData不是空的數(shù)組了,那么在add的時(shí)候,minCapacity=size+1;也就是minCapacity代表著elementData中增加之后的實(shí)際數(shù)據(jù)個(gè)數(shù),拿著它判斷elementData的length是否夠用,如果length
不夠用,那么肯定要擴(kuò)大容量,不然增加的這個(gè)元素就會(huì)溢出。 - grow 擴(kuò)容量 1.5倍
private void grow(int minCapacity) {
// 獲取數(shù)組的長度
int oldCapacity = elementData.length;
//新長度=舊長度+舊長度/2
int newCapacity = oldCapacity + (oldCapacity >> 1);
//判斷新長茺-最小的是否小于0
if (newCapacity - minCapacity < 0)
//小于0,說明新長度還是不夠,直接賦值minCapacity
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//大于0
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
//復(fù)制整個(gè)數(shù)組的元素到新數(shù)組,并賦值加原數(shù)組
elementData = Arrays.copyOf(elementData, newCapacity);
}
- hugeCapacity
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
//判斷是容量是否正常量
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//如果比最大允許的容量還大就取Integer最大值,否則就使用MAX_ARRAY_SIZE
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
添加元素完成
public void add(int index, E element) 添加到指定位置
public void add(int index, E element) {
//較驗(yàn)下標(biāo)是允許的范圍內(nèi)
rangeCheckForAdd(index);
//判斷是否要擴(kuò)容 上面的步驟
ensureCapacityInternal(size + 1); // Increments modCount!!
//從下標(biāo)index+1的開始的元素向后移到一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//賦值
elementData[index] = element;
//元素大小+1
size++;
}
- rangeCheckForAdd
private void rangeCheckForAdd(int index) {
//下標(biāo)是否小于0 或者比元素個(gè)數(shù)還大 拋出下標(biāo)越界異常 IndexOutOfBoundsException
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
set方法
public E set(int index, E element) {
// 較驗(yàn)下標(biāo)是允許的范圍內(nèi)
rangeCheck(index);
//找到下標(biāo)的元素
E oldValue = elementData(index);
//賦值為新值
elementData[index] = element;
//返回舊值
return oldValue;
}
- elementData
這個(gè)就是數(shù)組[index]
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
包含 contains
public boolean contains(Object o) {
//大于0就說明找到
return indexOf(o) >= 0;
}
indexOf
//循環(huán)查找 找到就返回索引,找不到返回-1
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
size
public int size() {
//返回元素的個(gè)數(shù)
return size;
}
public boolean isEmpty() {
//元素個(gè)數(shù)是否為空
return size == 0;
}
remove(int index)
下標(biāo)較驗(yàn)
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- remove
public E remove(int index) {
//判斷索引下標(biāo)是否正常
rangeCheck(index);
//修改次數(shù)+1
modCount++;
//獲取這個(gè)下標(biāo)上的元素
E oldValue = elementData(index);
//要移動(dòng)的長度 元素個(gè)數(shù)-下標(biāo)索引-1
// 比如:1,2,3,4,5 ,6 index是3 (值是4) size 6, 6 -3 -1 移動(dòng)2位
int numMoved = size - index - 1;
//判斷是否大于0,如果是最后一位就不用
if (numMoved > 0)
//從下標(biāo)+1位,向前移動(dòng)1位,移動(dòng)的長度是numMoved
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//元素最后一位賦值為空,并且數(shù)量-1
elementData[--size] = null; // clear to let GC do its work
//返回舊值
return oldValue;
}
remove(Object obj)
和上面的原理基本相同,但是要先找到這個(gè)元素的下標(biāo)索引
public boolean remove(Object o) {
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;
}
- fastRemove
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
clear 方法清空數(shù)組
public void clear() {
modCount++;
// clear to let GC do its work
for (int i = 0; i < size; i++)
//每個(gè)值都設(shè)置為空
elementData[i] = null;
//最后元素個(gè)數(shù)設(shè)置為0
size = 0;
}
transient Object[] elementData;
transient 標(biāo)記的字段表示序列化是不參與序列化,但ArrayList又實(shí)現(xiàn)的Serializable接口
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
實(shí)際上ArrayList重寫了序列化、反序列化方法
因?yàn)閑lementData會(huì)擴(kuò)容量,如果直接序列化會(huì)寫入很多NULL值,這時(shí)只序列化,實(shí)際的元素個(gè)數(shù),反序列化也一樣
先把元素個(gè)數(shù)寫入,再循環(huán)寫入每個(gè)元素
反序列化,先讀取元素個(gè)數(shù),再循環(huán)讀出每個(gè)元素
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
//這里先把元素個(gè)數(shù)寫入
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
// Read in size, and any hidden stuff
s.defaultReadObject();
// Read in capacity
s.readInt(); // ignored
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}