今天介紹常常使用的一個Java集合類——ArrayList(基於JDK1.8.0_121)。ArrayList在工做和平常面試中常常被使用或者提到。總的來講,工做中使用ArrayList主要是由於動態數組的方便性,面試中出現ArrayList常常是和LinkedList/Vector一塊兒出現,分析這三種集合的異同。java
圖片是直接從IntelliJ中導出來的,其中:藍色線條意味着繼承,綠色線條意味着接口實現。面試
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
咱們首先須要明白而且牢記在心裏的是,ArrayList本質上是一個數組,可是與Java中基礎的數組所不一樣的是,它可以動態增加本身的容量。
經過ArrayList的定義,能夠知道ArrayList繼承了AbstractList,同時實現了List,RandomAccess,Cloneable和java.io.Serializable接口。數組
繼承了AbstractList類,實現了List,意味着ArrayList是一個數組隊列,提供了諸如增刪改查、遍歷等功能。
實現了RandomAccess接口,意味着ArrayList提供了隨機訪問的功能。RandomAccess接口在Java中是用來被List實現,用來提供快速訪問功能的。在ArrayList中,即咱們能夠經過元素的序號快速獲取元素對象。
實現了Cloneable接口,意味着ArrayList實現了clone()函數,能被克隆。
實現了java.io.Serializable接口,意味着ArrayList可以經過序列化進行傳輸。dom
private static final int DEFAULT_CAPACITY = 10; transient Object[] elementData; private int size;
(1)ArrayList的默認容量爲10;
(2)elementData是"Object類型的數組",全部ArrayList元素都保存在elementData中。在ArrayList中,elementData是一個動態數組。須要注意的是,ArrayList經過構造函數ArrayList(int initialCapacity)定義初始量initialCapacity;
(3)size是動態數組的實際大小。函數
//ArrayList帶容量的構造函數 public ArrayList(int initialCapacity) { if (initialCapacity > 0) { //新建一個容量爲initialCapacity的數組 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } //ArrayList默認構造函數,默認爲空 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } // 構造一個包含指定元素的list public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } else { this.elementData = EMPTY_ELEMENTDATA; } }
第一個構造方法使用提供的initialCapacity來初始化elementData數組的大小。
第二個構造方法默認數組爲0。
第三個構造方法則將提供的集合轉成數組返回給elementData(返回若不是Object[]將調用Arrays.copyOf方法將其轉爲Object[])。this
public boolean add(E e) { //擴容判斷 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; } public void add(int index, E element) { //判斷index是否越界,錯誤產生IndexOutOfBoundsException rangeCheckForAdd(index); //進行擴容檢查 ensureCapacityInternal(size + 1); // Increments modCount!! //對數組進行復制,將空出的Index位置出入element,並將index後的全部數據後移一個位置。 System.arraycopy(elementData, index, elementData, index + 1, size - index); //將index上的數據設置爲element elementData[index] = element; //容量+1 size++; }
public E remove(int index) { //邊界檢查 rangeCheck(index); modCount++; //oldValue即要刪除的元素 E oldValue = elementData(index); //要複製的元素 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 return oldValue; } public boolean remove(Object o) { //對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; }
public E set(int index, E element) { //數組擴容 rangeCheck(index); //獲取要更新的位置的數據 E oldValue = elementData(index); //更新元素 elementData[index] = element; return oldValue; }
newCapacity = oldCapacity + (oldCapacity >> 1)