導(dǎo)讀
ArrayList可以看成是動態(tài)數(shù)組,初始化時(shí),如果沒有分配空間劳澄,則默認(rèn)為10。每次進(jìn)行添加新元素時(shí)蜈七,會對該數(shù)組的剩余空間進(jìn)行判斷秒拔,如果不夠了則會在原基礎(chǔ)上增加3/2+1個(gè)空間。刪除元素時(shí)飒硅,是先獲取要刪除元素的位置砂缩,然后把該位置后面的元素向前移動一位,并把數(shù)組的最后一位賦值為null三娩。刪除和新增元素用的都是native方法System.arrayCopy()庵芭。
看一下平時(shí)主要使用的一些方法。
public ArrayList(int paramInt)
{
if (paramInt < 0)
throw new IllegalArgumentException("Illegal Capacity: " + paramInt);
this.elementData = new Object[paramInt];
}
public ArrayList()
{
this(10);
}
public ArrayList(Collection<? extends E> paramCollection)
{
this.elementData = paramCollection.toArray();
this.size = this.elementData.length;
if (this.elementData.getClass() == [Ljava.lang.Object.class)
return;
this.elementData = Arrays.copyOf(this.elementData, this.size, [Ljava.lang.Object.class);
}
在ArrayList源碼中尽棕,頭三個(gè)方法ArrayList()均是初始化一個(gè)list的。從頭兩個(gè)方法可以看出彬伦,初始化ArrayList的時(shí)候,會創(chuàng)建一個(gè)Object數(shù)組滔悉,數(shù)組的大小可以是自己設(shè)定的一個(gè)值,也可以是系統(tǒng)默認(rèn)分配的10单绑。如果一開始傳入一個(gè)list的話回官,則會復(fù)制該list的參數(shù)到新初始化的ArrayList中。
public void trimToSize()
{
this.modCount += 1;
int i = this.elementData.length;
if (this.size >= i)
return;
this.elementData = Arrays.copyOf(this.elementData, this.size);
}
該方法是把list里的數(shù)組長度調(diào)整到原設(shè)定的長度(類中有設(shè)定了一個(gè)size來專門表示list的長度搂橙,list的size()方法返回的也正是這個(gè)size)因?yàn)槊看慰臻g不夠用時(shí)歉提,都會擴(kuò)增3/2的空間,所以list的長度和真正數(shù)組的長度是不一定相等的区转,參照下面方法苔巨。
public void ensureCapacity(int paramInt)
{
this.modCount += 1;
int i = this.elementData.length;
if (paramInt <= i)
return;
Object[] arrayOfObject = this.elementData;
int j = i * 3 / 2 + 1;
if (j < paramInt)
j = paramInt;
this.elementData = Arrays.copyOf(this.elementData, j);
}
這個(gè)方法在給list添加新元素的時(shí)候會先執(zhí)行,主要是判斷當(dāng)前l(fā)ist長度是否夠用废离,如果不夠侄泽,會新建一個(gè)數(shù)組,該數(shù)組的空間會在原數(shù)組空間基礎(chǔ)上增加3/2倍蜻韭,并把原數(shù)組的元素全部復(fù)制到新建的數(shù)組中悼尾。
public int size()
{
return this.size;
}
public boolean isEmpty()
{
return this.size == 0;
}
這兩個(gè)方法很好理解柿扣,獲取list的長度和判斷l(xiāng)ist是否為空。
public boolean contains(Object paramObject)
{
return indexOf(paramObject) >= 0;
}
public int indexOf(Object paramObject)
{
int i;
if (paramObject == null)
for (i = 0; i < this.size; ++i)
if (this.elementData[i] == null)
return i;
else
for (i = 0; i < this.size; ++i)
if (paramObject.equals(this.elementData[i]))
return i;
return -1;
}
上面的方法是用于判斷l(xiāng)ist中是否包含某個(gè)元素的闺魏,在indexOf()
中只要檢測到有一個(gè)元素是符合條件的未状,則返回該元素的位置。
public int lastIndexOf(Object paramObject)
{
int i;
if (paramObject == null)
for (i = this.size - 1; i >= 0; --i)
if (this.elementData[i] == null)
return i;
else
for (i = this.size - 1; i >= 0; --i)
if (paramObject.equals(this.elementData[i]))
return i;
return -1;
}
該方法用于獲取一個(gè)元素在list中最后位置析桥,它是從數(shù)組的最后一個(gè)元素開始做比對的司草,所以,不管這個(gè)數(shù)組中有幾個(gè)相同的元素烹骨,都只會獲取到最后一個(gè)相同的元素翻伺,并返回它的位置。
private void RangeCheck(int paramInt)
{
if (paramInt < this.size)
return;
throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
}
public E get(int paramInt)
{
RangeCheck(paramInt);
return this.elementData[paramInt];
}
public E set(int paramInt, E paramE)
{
RangeCheck(paramInt);
Object localObject = this.elementData[paramInt];
this.elementData[paramInt] = paramE;
return localObject;
}
get方法獲取某個(gè)位置的元素沮焕,set方法會修改某個(gè)位置的參數(shù)吨岭,并返回原參數(shù)。其中的RangeCheck()方法是用于判斷該位置是否在list長度范圍內(nèi)的峦树。
public boolean add(E paramE)
{
ensureCapacity(this.size + 1);
this.elementData[(this.size++)] = paramE;
return true;
}
public void add(int paramInt, E paramE)
{
if ((paramInt > this.size) || (paramInt < 0))
throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
ensureCapacity(this.size + 1);
System.arraycopy(this.elementData, paramInt, this.elementData, paramInt + 1, this.size - paramInt);
this.elementData[paramInt] = paramE;
this.size += 1;
}
add方法辣辫,用過list的應(yīng)該都很熟悉了,如果有傳入具體要放置的位置魁巩,則多了對原數(shù)組的位置移動操作急灭;沒有的話,則在數(shù)組的末尾加入該元素谷遂。
public E remove(int paramInt)
{
RangeCheck(paramInt);
this.modCount += 1;
Object localObject = this.elementData[paramInt];
int i = this.size - paramInt - 1;
if (i > 0)
System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
this.elementData[(--this.size)] = null;
return localObject;
}
public boolean remove(Object paramObject)
{
int i;
if (paramObject == null)
for (i = 0; i < this.size; ++i)
{
if (this.elementData[i] != null)
continue;
fastRemove(i);
return true;
}
else
for (i = 0; i < this.size; ++i)
{
if (!paramObject.equals(this.elementData[i]))
continue;
fastRemove(i);
return true;
}
return false;
}
private void fastRemove(int paramInt)
{
this.modCount += 1;
int i = this.size - paramInt - 1;
if (i > 0)
System.arraycopy(this.elementData, paramInt + 1, this.elementData, paramInt, i);
this.elementData[(--this.size)] = null;
}
arrayCopy方法如下
public static void arraycopy(Object src,//源數(shù)組葬馋;
int srcPos,//源數(shù)組要復(fù)制的起始位置;
Object dest,//目的數(shù)組肾扰;
int destPos,//目的數(shù)組放置的起始位置畴嘶;
int length //復(fù)制的長度。
)
這幾個(gè)方法都是刪除元素的操作集晚。通過指定刪除的位置窗悯,指定刪除的元素來刪除元素;兩個(gè)刪除的方法最后都是調(diào)用了fastRemove來刪除元素的偷拔,fastRemove方法則是通過調(diào)用系統(tǒng)方法實(shí)現(xiàn)自我復(fù)制蒋院,把要刪除的元素后面的元素都向前移動一位,覆蓋掉了要刪除的元素莲绰,并把數(shù)組的最后一個(gè)元素設(shè)置為null欺旧。
public void clear()
{
this.modCount += 1;
for (int i = 0; i < this.size; ++i)
this.elementData[i] = null;
this.size = 0;
}
clear方法會把數(shù)組中所有元素賦值null,并把size賦值上0蛤签。在沒有被回收內(nèi)存之前切端,數(shù)組空間也都還在。
public boolean addAll(Collection<? extends E> paramCollection)
{
Object[] arrayOfObject = paramCollection.toArray();
int i = arrayOfObject.length;
ensureCapacity(this.size + i);
System.arraycopy(arrayOfObject, 0, this.elementData, this.size, i);
this.size += i;
return i != 0;
}
public boolean addAll(int paramInt, Collection<? extends E> paramCollection)
{
if ((paramInt > this.size) || (paramInt < 0))
throw new IndexOutOfBoundsException("Index: " + paramInt + ", Size: " + this.size);
Object[] arrayOfObject = paramCollection.toArray();
int i = arrayOfObject.length;
ensureCapacity(this.size + i);
int j = this.size - paramInt;
if (j > 0)
System.arraycopy(this.elementData, paramInt, this.elementData, paramInt + i, j);
System.arraycopy(arrayOfObject, 0, this.elementData, paramInt, i);
this.size += i;
return i != 0;
}
添加一個(gè)list數(shù)據(jù)到list中顷啼,第一個(gè)addAll是直接在list后面添加新的數(shù)據(jù)踏枣,第二個(gè)addAll是在指定的位置插入新增的數(shù)據(jù)昌屉。