前引
ArrayList是什麼?
ArrayList(JDK1.6)源碼:
private transient Object[] elementData;
private int size;
protected transient int modCount = 0;(來之父類AbstractList,ArrayList不存在)
這個elementData就是用來存放數據的object數組。size是數組的大長度,代表的是ArrayList的所存貯的數據的容量。modCount用來記錄容器被改變的次數(對理解沒什麼用,後文不再解釋這個變量)。 public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
this(10);
}
這段代碼是初始化ArrayList用的。從中我們可以看出,實例ArrayList有兩種方法,而我們不一般不帶參數的時候,ArrayList默認的大小是10.即產生一個容量爲10的elementData的object數組。 public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
這一段是爲了確保數組可以存放下不停增多的數據,而專門設計的增加數組的長度的方法。從中 可以看出實現思路是:當需要存放數據到elementData數組中去的時候,會傳入minCapcity(表示該數組應存入的總數據量),如果minCapcity大於現在的數組的長度,就產生一個新的數組,容量爲以前的1.5倍+1,如果仍然小於,就直接將容量設置爲minCapcity。然後再將之前存放在原數組的數據複製到新的數組中去,就實現了整個數組的擴容!
public int size() {
return size;
}
size就是elementData的長度。 public boolean isEmpty() {
return size == 0;
}
返回size==0的判斷結果indexOf(Object o):
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;
}
傳入一個對象,返回其索引。 可以看出這個方法只是將傳入的對象和elementData中的每個元素進行比較,然後再返回其數組下標號。找不到的話,就返回-1。contains(Object o)也只是調用了這個方法而已。 public int lastIndexOf(Object o) {
if (o == null) {
for (int i = size-1; i >= 0; i--)
if (elementData[i]==null)
return i;
} else {
for (int i = size-1; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
可以看見lastIndexOf方法和indexOf是如此的相似,只是將遍歷方向改變了一下就又多了一個方法,哈哈! public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
}
set(index,object) public E set(int index, E element) {
RangeCheck(index);
E oldValue = (E) elementData[index];
elementData[index] = element;
return oldValue;
}
可以發現很多操作都只是在操作數組而已!畢竟ArrayList就是數組。add(o):
public boolean add(E e) {
ensureCapacity(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
add方法也是如此,只是此處需要判斷是否要擴容add(index,object):
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
在某個位置插入一個對象,這段代碼難得也就這就話:System.arraycopy(elementData, index, elementData, index + 1, size - index); 其實這句好的意思是:將elementData從其第index和後面的元素,複製到elementData的第index+1和之後的位置,共複製size-index個元素,這樣就是實現了將第index爲元素騰空,讓外界傳進來的object佔據這個寶座。這也是前面擴容的時候使用的是size+1而不是size的原因(確保數組複製時弄的size+1不會越界) public E remove(int index) {
RangeCheck(index);
modCount++;
E oldValue = (E) elementData[index];
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // Let gc do its work
return oldValue;
}
可以發現和add是差不多的,而且還不許要考慮擴容的問題。同樣的remove(object)相比起來,就多了一個判斷該對象的index在哪,然後直接調用這個方法就行了。