ArrayList Source Code
說明
承了RanddomAccess —->遍歷的話用for最好
elementData是數組 所以在順序插入和隨機訪問的情況下使用這個最好
list可以放入重複的值
構造方法
先將繼承集合接口Collection的C(如hashset)轉化爲數組 如果數組長度不是0 而且對象不是Object[] (elementData類型)則將轉成Object[]
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
方法
trimToSize()
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
說明:
Trims the capacity of this ArrayList instance to be the list’s current size. An application can use this operation to minimize the storage of an ArrayList instance.
將ArrayList實例的容量 變爲list的當前大小 . 應用可以使用這個操作最小化ArrayList實例的存儲
獲取ArrayList的元素個數是用size. 而length是ArrayList申請的容量大小. 便於不用每次增加的時候都去進行擴容操作.在isEmpty()方法裏判斷是否爲null的時候 直接用size==0判斷
modCount是什麼? The number of times this list has been structurally modified
這個字段主要防止多線程操作的情況下 ArrayList發生結構性的變化. 例如一個線程正在遍歷 而另一個線程正在remove. 在遍歷的過程中 會發現某個元素爲null 這時 modCount 會告訴迭代器 讓其拋出ConcurrentModificationException.如果沒有這一個變量,那麼系統肯定會報異常ArrayIndexOutOfBoundsException,這樣的異常顯然不是應該出現的(這些運行時錯誤都是使用者的邏輯錯誤導致的,我們的JDK那麼高端,不會出現使用錯誤,我們只拋出使用者造成的錯誤,而這個錯誤是設計者應該考慮的),爲了避免出現這樣的異常,定義了檢查。—從這裏也可以看出 ArrayList是非線程安全的
參考知乎:https://www.zhihu.com/question/24086463/answer/64717159
add()
說明:Appends the specified element to the end of this list 添加指定元素到list尾部
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
在 空參初始化的時候 elementData=DFAULTCAPACITY_EMPTY_ELEMENTDATA 然後返回最小容量是默認容量 10 還是size+1 .然後確定明確的容量ensureExplicitCapacity 如果大於10 則擴容 grow
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 再判斷一下新數組的容量夠不夠,夠了就直接使用這個長度創建新數組,
// 不夠就將數組長度設置爲需要的長度
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);
}
如何擴容?
看到第二行 就知道 容量變成原來的1.5倍 然後copy到新的數組
更詳細的參考:https://blog.csdn.net/wangb_java/article/details/79515302
remove(int index)
說明 Removes the element at the specified position in this list Shifts any subsequent elements to the left 移除list指定位置的元素 將之後的所有元素向左轉移
public E remove(int index) {
rangeCheck(index);//判斷是否越界
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;//獲取index位置開始到最後一個位置的個數
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved); // 將elementData數組index+1位置開始拷貝到elementData從index開始的空間
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
batchRemove(Collection
private boolean batchRemove(Collection<?> c, boolean complement) {
final Object[] elementData = this.elementData;
int r = 0, w = 0;
boolean modified = false;
try {
for (; r < size; r++)
if (c.contains(elementData[r]) == complement)
elementData[w++] = elementData[r];// 直接將r位置的元素賦值給w位置的元素,w自增
} finally {
//保留與AbstractCollection的行爲兼容性 防止拋出異常導致上面r的右移過程沒完成
// Preserve behavioral compatibility with AbstractCollection,
// even if c.contains() throws.
if (r != size) {
System.arraycopy(elementData, r,
elementData, w,
size - r);
w += size - r;
}
if (w != size) {
// clear to let GC do its work
for (int i = w; i < size; i++)
elementData[i] = null;
modCount += size - w;
size = w;
modified = true;
}
}
return modified;
}
int indexOf(Object o)
說明:Returns the index of the first occurrence of the specified element in this list, or -1 if this list does not contain the element. More formally, returns the lowest index i such that (o==null ? get(i)==null : o.equals(get(i))), or -1 if there is no such index.
大體意識是 找到指定元素o在list第一次出現的位置. 如果 list中沒有o則返回-1.
public int indexOf(Object o) {
if (o == null) {//元素o 爲null 則得到該數組中第一個元素爲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;
}
Object clone()
說明:Returns a shallow copy of this ArrayList instance. (The elements themselves are not copied.)
返回ArrayList實例的淺複製 元素本身不被複制
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
這個 淺複製 和 深複製 的區別 參考:https://blog.csdn.net/accp_fangjian/article/details/2423252
toString()
說明:這個方法是繼承父類AbstractCollection的Object的 toString()方法.
一般 對數組toString()輸出的的值沒有太大的意義.但是集合的toString()是打印出集合中的內容,就是因爲 AbstractCollection
public String toString() {
Iterator<E> it = iterator();
if (! it.hasNext())
return "[]";
StringBuilder sb = new StringBuilder();//在不考慮 線程安全的情況下 字符串拼接最好用StringBuilder
sb.append('[');
for (;;) {
E e = it.next();
sb.append(e == this ? "(this Collection)" : e);
if (! it.hasNext())
return sb.append(']').toString();
sb.append(',').append(' ');
}
}