ArrayList簡介:
java.util.ArrayList 是我們最常用的一個類,ArrayList 底層是動態陣列,讀者可以把它理解為陣列的實現
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
}
如上程式碼我們可以看到 ArrayList 繼承了 AbstractList() 抽象類,並實現了 List, RandomAccess, Cloneable, Serializable 介面
AbstractList :
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {}
可以看到AbstractList 繼承了 AbstractCollection 介面, 並實現了List 介面
AbstractCollection :
public abstract class AbstractCollection<E> implements Collection<E> {}
AbstractCollection 是一個抽象類,實現了Collection 介面,並提供了某些方法的具體實現。
Collection:
Collection 是一個頂級介面,是很多集合類的頂級介面,繼承了Iterable ,支援輕量級遍歷其中元素
public interface Collection<E> extends Iterable<E> {}
List :
ArrayList 實現了List介面,List 也是一個和Collection 媲美的頂級介面,繼承了Collection 介面
public interface List<E> extends Collection<E> {}
它是許多集合類的父類,
eg:
List list = new ArrayList();
List list2 = new LinkedList();
RandomAccess
RandomAccess 也是一個頂級介面,實現了此介面的類支援隨機訪問
Cloneable
Cloneable 介面是一個頂級介面,實現了此介面的類支援淺拷貝
Serializable
實現此介面的類支援序列化的功能
類之間的繼承關係如圖
ArrayList 相關方法介紹
trimToSize()
程式碼表示
實踐才是檢驗真理最好的方式:
import java.util.*;
/**
* 詳述ArrayList 基本用法
*/
public class ArrayListTest {
private static class SortList implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
Integer i1 = Integer.valueOf(o1);
Integer i2 = Integer.valueOf(o2);
if(i1 < i2){
return -1;
}else if(i1 == i2){
return 0;
}
return 1;
}
}
// 使用可變引數,能夠接受任意個引數
public Set<String> putSet(String...args){
Set<String> sets = new HashSet<>();
for(String str : args){
sets.add(str);
}
return sets;
}
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("111");
list.add("222");
// 在指定位置新增元素
list.add(0,"333");
System.out.println(list);
// 進行外部排序
list.sort(new SortList());
System.out.println(list);
list.clear();
System.out.println(list.size());
// 使用addAll新增元素
ArrayListTest at = new ArrayListTest();
list.addAll(at.putSet("1","2","3"));
Iterator<String> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
// 移除所有元素
it.remove();
}
System.out.println("list是否為空 ? " + list.isEmpty());
list.add("111");
// 在指定位置新增一個set集合
list.addAll(0,at.putSet("1","2","3"));
System.out.println(list);
// 是否包含指定元素
if(list.contains("111")) {
list.remove("111");
}
System.out.println(list);
System.out.println(list.indexOf("1"));
// 注意subList()這個方法是左開右閉區間,Java 中很多都是類似的
System.out.println(list.subList(0,3));
// 擴大list的容量
list.ensureCapacity(10);
// 去掉list空閒的容量
list.trimToSize();
// 獲取某個特定的元素
System.out.println(list.get(1));
// 建立一個list的雙向連結串列
ListIterator<String> listIterator = list.listIterator();
while(listIterator.hasNext()){
// 移到list的末端
System.out.println(listIterator.next());
}
System.out.println("--------------------------");
while (listIterator.hasPrevious()){
// 移到list的首端
System.out.println(listIterator.previous());
}
// 把list轉換為陣列
Object[] objects = list.toArray();
System.out.println("objects = " + objects);
}
}
相關方法原始碼分析
原始碼的具體分析是根據上面的程式碼示例得出,因為只看原始碼好像並不能看懂什麼,需要根據具體的程式碼一步一步debug 進行跟蹤
add()方法
解釋:新增指定的元素在list的末尾
/**
* 新增指定的元素在list的末尾
*/
// 假設第一次新增的是 "111"
public boolean add(E e) {
// size是0,所以size + 1 傳的是1
ensureCapacityInternal(size + 1);
// elementData[0] = 111 , size++ = 1
elementData[size++] = e;
return true;
}
// 此方法用來進行list 擴容
private void ensureCapacityInternal(int minCapacity) {
// 此時elementData 並沒有儲存元素,為0
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 則minCapacity 取預設初始容量和minCapacity 的最大值 (取1 和 10的最大值)
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
// 確保清晰的容量(最小容量與List元素的比較)
ensureExplicitCapacity(minCapacity);
}
// 在list中新增了一個元素,所以會導致結構化的修改,"結構化的修改"見下面解釋
// 此時minCapacity 為 10
private void ensureExplicitCapacity(int minCapacity) {
// 次數 + 1
// 這個列表被修改結構的次數(比如新增和刪除元素)會用modCount表示. 結構化修改是指的是能夠
// 改變列表容量的操作,或者其他方式改變它,導致遍歷的過程會產生錯誤的結果。
modCount++;
// overflow-conscious code
// 10 - 0 > 0 走grow 方法
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 增加容量確保容納足夠的元素
*
* 引數傳過來的是10
*/
private void grow(int minCapacity) {
// overflow-conscious code
// oldCapacity = 0
int oldCapacity = elementData.length;
// newCapacity = 0
int newCapacity = oldCapacity + (oldCapacity >> 1);
// newCapacity - minCapacity = -10
if (newCapacity - minCapacity < 0)
// newCapacity = 10
newCapacity = minCapacity;
// MAX_ARRAY_SIZE = 陣列分配的最大空間 = 2147483639
// 一般情況下不會比 MAX_ARRAY_SIZE 還要大
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 底層還是用的System.arraycopy(), 關於System.arrayCopy() 讀者可以參考我的另一篇部落格
elementData = Arrays.copyOf(elementData, newCapacity);
}
相關常用的基本資料型別包裝類的值: Java基本資料型別包裝類常用的值
add(int index, E element)
解釋:在list中指定位置插入指定的元素,如果當前位置有元素,就移動當前位置的元素
/**
* 在list中指定位置插入指定的元素,如果當前位置有元素,就移動當前位置的元素
* 要插入的位置的後面所有元素的位置向前 + 1
*
*/
public void add(int index, E element) {
// 檢查 0 這個位置是否越界
rangeCheckForAdd(index);
// 不再贅述,讀者可以自行debug
ensureCapacityInternal(size + 1); // Increments modCount!!
// 因為從當前位置插入元素,所以當前位置及後面的元素都會向後移動
// 使用System.arraycopy 進行陣列複製
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
// 為當前元素賦值
elementData[index] = element;
size++;
}
/**
* 為add 和 addall 提供的範圍檢查, 不符合條件,丟擲IndexOutOfBoundsException 異常
*/
private void rangeCheckForAdd(int index) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
Clear()
解釋:移除列表中的所有元素
/**
* 移除list列表中所有的元素,列表會變為空列表在呼叫此方法後
*
*/
public void clear() {
// 修改次數 + 1
modCount++;
// clear to let GC do its work
// 把每個變數置空,GC進行回收
for (int i = 0; i < size; i++)
elementData[i] = null;
// 列表的長度變為0
size = 0;
}
這個方法的原始碼理解起來還是比較簡單的
addAll(Collection<? extends E> c)
解釋: 把一個Collection集合新增到list末尾
/**
* 把一個Collection集合(實現了此介面的類)新增到list的末尾,按著迭代的順序返回。
* 此操作的行為是如果在此方法呼叫的過程中修改了Collection(實現了此介面的類)的話,
* 那麼這個操作不會成功
*/
public boolean addAll(Collection<? extends E> c) {
// 把Collection 轉換為 Object[] 陣列
Object[] a = c.toArray();
// 陣列中有三個元素
int numNew = a.length;
// 因為上面的操作呼叫了一次list.clear()方法,所以list.size = 0
ensureCapacityInternal(size + numNew); // Increments modCount
// 一句話解釋: 把a 陣列中0個位置的元素 複製到 elementData陣列中 第size個位置的元素,
// 複製的長度為 numNew
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
// toArray()方法:
/**
* 返回一個陣列,包含了所有的元素(從第一個元素到最後一個元素)
* 返回的陣列是很"安全的"因為列表沒有引用可以維持(換句話說,這個方法必須分配一個新陣列)
* 呼叫者因此可以任意修改返回的陣列
* 這個方法是陣列 和 集合之間的橋樑
*/
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
iterator(), hasNext(), next()
解釋:Iterator方法用於遍歷list中的元素,返回一個Itr 的內部類,hasNext()方法用於判斷list 中是否還有未遍歷的元素,next()方法用於獲取下一個元素
/**
* 以適當的順序返回此列表中元素的迭代器
* 返回的iterator 支援fail-fast 機制
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* Itr 是一個內部類,實現了Iterator介面,可支援快速遍歷
*/
private class Itr implements Iterator<E> {
// 下一個元素返回的下標
int cursor; // index of next element to return
// 最後一個元素返回的下標, 如果沒有返回-1
int lastRet = -1; // index of last element returned; -1 if no such
// expectedModCount 期望的修改次數,預設是和modCount(修改次數相同,用於iterator判斷fail-fast機制)
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
// 判斷遍歷的過程中是否觸發fail-fast機制
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
// 如果lastRet < 0,說明 lastRet 沒有被改變,
// 所以應該是沒有呼叫next()就呼叫了remove()
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
cursor = i;
lastRet = i - 1;
checkForComodification();
}
// 如果修改次數不滿足預期修改次數的話,丟擲異常
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
addAll(int index,Collection<? extends E> c)
解釋:在某個位置新增Collection集合
/**
* 在指定的位置下標插入一個Collection集合
*/
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
// 需要移動的元素個數
int numMoved = size - index;
if (numMoved > 0)
// 第一次陣列複製,從elementData中的index位置開始,複製到index + numNew位置上,複製numMoved個元素
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
// 第二次陣列複製,從a 陣列中的第0個位置開始,複製到elementData第index位置上你,複製numNew個元素
System.arraycopy(a, 0, elementData, index, numNew);
size += numNew;
return numNew != 0;
}
contains(Object o)
解釋:判斷list列表是否包含某個元素
/**
* 返回true,如果這個列表包含指定的元素
* 更進一步來說,當且僅當list包含至少一個元素的情況下,返回true
*/
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
/**
* 返回列表中第一次出現指定元素的下標值,如果不包含指定元素,則返回-1。
* 更進一步來說,返回最小的索引當(o == null ? get(i) == null : o.equals(get(i)))的時候
* 或者返回-1 沒有此下標值
*
*/
public int indexOf(Object o) {
// 如果o這個物件等於null,就判斷elementData中是否有空元素,如果有,返回
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
// 如果不為null,返回這個值的儲存位置
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
remove(Object o)
解釋:移除list中的某個元素
/**
* 如果存在,則移除list中某個第一次出現的元素。如果這個list不包含指定元素,就不會改變
*
*/
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;
}
/*
* 私有的移除方法,並且不返回被移除的元素,這個原始碼比較簡單
*/
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
}
indexOf(Object o)
解釋:檢索某個元素的位置
此原始碼和contains(Object o)中呼叫的indexOf 原始碼相同
subList(int fromIndex, int toIndex)
解釋:返回list列表的一個片段
/**
* 返回list列表中的一部分檢視(相當於list片段),[fromIndex,toIndex),如果fromIndex 和
* toIndex 相同的話,表明這個list為空,這個返回的list被返回,所以在list中並沒有結構的改變
* 這個返回的list片段支援所有的list操作
*/
public List<E> subList(int fromIndex, int toIndex) {
// subList 範圍檢查
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent;
private final int parentOffset;
private final int offset;
int size;
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
}
ensureCapacity(int minCapacity)
解釋:擴大list的容量
/**
* 增加ArrayList例項的容量,如果必須的話,確保它能持有最小容量的元素
*/
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);
}
}
trimToSize()
解釋:去掉list空閒的容量
/**
* 去掉ArrayList中的多餘空間
*/
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = (size == 0)
? EMPTY_ELEMENTDATA
: Arrays.copyOf(elementData, size);
}
}
sort(Comparator<? super E> c)
sort 方法接收一個自定義比較器進行自定義比較,下面來看具體的原始碼
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
// 根據上面程式碼分析,此時modCounnt 已經被修改過三次(新增了三個元素)
final int expectedModCount = modCount;
// 陣列外部排序
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}