基於java10.1
java
若是想讀讀源碼測試功力,或讀讀源碼修養身心,或讀讀源碼知足自虐傾向,我建議第一個類是:ArrayList
第1、經常使用----因此用法比較熟悉,看完源碼你也會更明白如何去用
第2、相對簡單----1595行代碼,刨去註釋的一大堆也沒有太多,仍是hold的住的git
void arraycopy( Object src, //源數組 int srcPos,//源數組中的起始位置 Object dest,//目標數組 int destPos,//目的地數據中的起始位置 int length);//要複製的數組元素的數量
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//serialVersionUID來驗證版本一致性 private static final long serialVersionUID = 8683452581122892189L; //默認列表的容量 private static final int DEFAULT_CAPACITY = 10; //一個空的Object數組--空數組(本文中別名:空1) private static final Object[] EMPTY_ELEMENTDATA = {}; //另外一個空的Object數組--默認容量空數組(本文中別名:空2) private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //列表中盛放的數組 transient Object[] elementData; //非私有來簡化內部類訪問 //內部元素個數 private int size; //最大數組尺寸,這裏是Integer最大值-8 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
使用無參構造ArrayList,在未添加元素前,內部數組的長度是爲0。在添加第一個元素時,纔會擴容到10github
//無參構造:elementData=空2 public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
//入參initialCapacity:初始容量 public ArrayList(int initialCapacity) { if (initialCapacity > 0) {//入參>0有效 //建立長度爲入參的Object數組 this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else {//入參<0異常 throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } }
// 入參c:已有的容器對象 public ArrayList(Collection<? extends E> c) { elementData = c.toArray();//傳入的集合轉化爲數組並賦值給elementData //獲取數組長度賦值值給size,當size不爲0 if ((size = elementData.length) != 0) { if (elementData.getClass() != Object[].class) //Arrays.copyOf見:A--01 elementData = Arrays.copyOf(elementData, size, Object[].class); } else {//入參 = 0 時:elementData=空1 this.elementData = EMPTY_ELEMENTDATA; } }
將一個數組拷貝指定長度,變爲另外一種類型的數組編程
@param <U> 初始數組類型 @param <T> 返回數組類型 @param original 被拷貝數組 @param newLength 拷貝的長度 @param newType 返回的數組類型 @return public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
modCount:父類AbstractList中的protected變量,每次添加和移除都會+1,記錄全部的修改次數
做用:在Iterator使用時校驗指望修改的次數與真實修改次數是否相同數組
*@param e 添加的元素 public boolean add(E e) { modCount++;//列表在結構上修改的次數 add(e, elementData, size);//此處調用三參的添加方法:見:m1-1 return true;//返回是否添加成功 }
*@param e 添加的元素 *@param elementData 數組 *@param s 索引位置 private void add(E e, Object[] elementData, int s) { //要添加的索引爲等於數組的長度時進行擴容操做 if (s == elementData.length) elementData = grow();//grow()返回一個擴容後的數組:見:m-1-1 //將傳入的元素放到數組的最後一位 elementData[s] = e;(注:因爲數組標號從零開始,新數組長度s+1,最後一個元素下標號爲s) size = s + 1;//將成員變量size+1 }
擴容操做微信
private Object[] grow() { return grow(size + 1);//調用了一參的grow()方法 } *@param minCapacity 最小容量 private Object[] grow(int minCapacity) { //newCapacity(minCapacity)擴容核心操做:見m-1-1-1 return elementData = Arrays.copyOf(elementData,newCapacity(minCapacity)); }
擴容核心操做: 最小容量size+1,舊容量:數組長,新容量:1.5倍舊容量
拿教室舉例:minCapacity就是班級學生數量+1,oldCapacity就是擴建前的座位數,newCapacity就是擴建後的座位數dom
*@param minCapacity 最小容量 private int newCapacity(int minCapacity) { //oldCapacity:舊容量 newCapacity:1.5倍舊容量 int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1);//即+50% if (newCapacity - minCapacity <= 0) { //新容量小於等於最小容量 //若是elementData=空2,擴容到DEFAULT_CAPACITY(即10),這就是分空1和空2的目的 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) return Math.max(DEFAULT_CAPACITY, minCapacity); if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return minCapacity; } //新容量大於最小容量時, newCapacity沒達到最大尺寸返回newCapacity,不然hugeCapacity(minCapacity) return (newCapacity - MAX_ARRAY_SIZE <= 0) ? newCapacity : hugeCapacity(minCapacity); } //minCapacity大於數組最大尺寸,返回整型的最大值,不然返回數組最大尺寸 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE)? Integer.MAX_VALUE: MAX_ARRAY_SIZE; }
* @param 插入的索引位置 * @param 插入的元素 public void add(int index, E element) { rangeCheckForAdd(index);//m2-1:檢查索引合法性 modCount++; final int s;//局部變量,記錄方法執行前size值 Object[] elementData//局部變量,記錄方法執行前elementData數組 if ((s = size) == (elementData = this.elementData).length) elementData = grow();//擴容1.5倍 System.arraycopy(elementData, index, elementData, index + 1, s - index);//m2-2:核心方法 elementData[index] = element; size = s + 1; }
private void rangeCheckForAdd(int index) { if (index > size || index < 0)//索引在(0,size)以外報異常 throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); }
//將[源數組src]從[指定位置srcPos]選取連續[長度length]個元素複製到[目標數組dest]的[指定位置destPos]。 public static native void arraycopy( Object src, //源數組 int srcPos,//源數組中的起始位置 Object dest,//目標數組 int destPos,//目的地數據中的起始位置 int length);//要複製的數組元素的數量
* @param 已有的容器對象 * @return 列表是否已被修改 */ public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray();//將容器對象轉化爲數組a modCount++;//修改次數+1 int numNew = a.length;//臨時變量numNew記錄a的長度 if (numNew == 0)//a的長度爲0 return false;//說明列表未被修改 Object[] elementData;//臨時變量elementData:數組 final int s;//臨時變量s:數組長度 //加入的元素大於數組容積和當前元素個數之差,也就是放入這些元素後會佔滿 if (numNew > (elementData = this.elementData).length - (s = size)) //擴容 elementData = grow(s + numNew); //將a數組,從0開始,拷貝numNew個元素到elementData數組的s索引處 System.arraycopy(a, 0, elementData, s, numNew); size = s + numNew;//維護size return true;////說明列表被修改 }
public boolean addAll(int index, Collection<? extends E> c) { rangeCheckForAdd(index);//見:m2-1 Object[] a = c.toArray(); modCount++; int numNew = a.length; if (numNew == 0) return false; Object[] elementData; final int s; if (numNew > (elementData = this.elementData).length - (s = size)) elementData = grow(s + numNew);//至此同上m3 int numMoved = s - index;//添加的位置以後的元素個數 if (numMoved > 0)//說明index在元素個數以內 //將elementData數組,從index開始,拷貝numMoved個元素到elementData數組的index + numNew索引處 //至關於挪一下索引位後的元素 System.arraycopy(elementData, index, elementData, index + numNew, numMoved); //將a數組,從0開始,拷貝numNew個元素到elementData數組的index索引處 System.arraycopy(a, 0, elementData, index, numNew); size = s + numNew; return true; }
public E remove(int index) { Objects.checkIndex(index, size);//檢查索引合法性 final Object[] es = elementData;//將集合賦予臨時變量es E oldValue = (E) es[index];//臨時變量記錄刪除值 fastRemove(es, index);//m5-1:刪除的核心方法 return oldValue;//返回刪除的值 }
/** * 私有的移除方法:跳過邊界檢查而且不反會移除的值 */ private void fastRemove(Object[] es, int i) { modCount++;//修改次數+1 final int newSize;//新尺寸:元素總量-1 if ((newSize = size - 1) > i)//索引在元素總量-1以內 //將es數組,從i + 1開始,拷貝size - (i+1)個元素到es數組的i索引處 System.arraycopy(es, i + 1, es, i, newSize - i); es[size = newSize] = null; }
public boolean remove(Object o) { final Object[] es = elementData; final int size = this.size; int i = 0; found: { if (o == null) { for (; i < size; i++) if (es[i] == null) break found; } else { for (; i < size; i++) if (o.equals(es[i])) break found; } return false; } //尋找到第一次出現的指定元素索引位置 fastRemove(es, i);//m5-1:刪除的核心方法 return true; }
public boolean removeAll(Collection<?> c) { return batchRemove(c, false, 0, size);//batchRemove見:m7-1 }
boolean batchRemove(Collection<?> c, boolean complement, final int from, final int end) { Objects.requireNonNull(c); final Object[] es = elementData;//es變量記錄當前數組 int r; // Optimize for initial run of survivors for (r = from;; r++) { if (r == end)//沒有找到該元素 return false; if (c.contains(es[r]) != complement)//包含但尚未所有掃描 break; } int w = r++; try { for (Object e; r < end; r++) if (c.contains(e = es[r]) == complement) es[w++] = e; } catch (Throwable ex) { System.arraycopy(es, r, es, w, end - r); w += end - r; throw ex; } finally { modCount += end - w; //shiftTailOverGap:見m7-1-1 shiftTailOverGap(es, w, end); } return true; }
private void shiftTailOverGap(Object[] es, int lo, int hi) { //將es數組,從hi開始,拷貝size - hi個元素到es數組的lo索引處 System.arraycopy(es, hi, es, lo, size - hi); for (int to = size, i = (size -= hi - lo); i < to; i++) es[i] = null;//將移除的元素置空 }
/** * 返回列表中指定位置的元素 */ public E get(int index) { //m8-1:檢查索引是否合法(1.9開始有) Objects.checkIndex(index, size); return elementData(index);//m8-2 }
public static int checkIndex(int index, int length) { return Preconditions.checkIndex(index, length, null);//m8-1-1 }
//判斷索引值是否在(0,length) public static <X extends RuntimeException> int checkIndex(int index, int length, BiFunction<String, List<Integer>, X> oobef) { if (index < 0 || index >= length) throw outOfBoundsCheckIndex(oobef, index, length);//這就是常常遇到的角標越界 return index; }
E elementData(int index) { return (E) elementData[index];//返回數組在索引上的值 }
public E set(int index, E element) { //檢查索引是否越界 Objects.checkIndex(index, size); //記錄舊值 E oldValue = elementData(index); //設置新值 elementData[index] = element; //返回舊值 return oldValue; }
public int size() { return size; }
public boolean isEmpty() { return size == 0; }
public void clear() { modCount++;//操做數+1 final Object[] es = elementData;//es存儲當前數組 for (int to = size, i = size = 0; i < to; i++) es[i] = null;//所有置空 }
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;//從頭開始找,直到相等時,返回i } return -1;//找不到返回-1 }
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;//從後往前找,直到相等時,返回i } return -1;//找不到返回-1 }
public boolean contains(Object o) { return indexOf(o) >= 0;//找到有索引就ok }
public Object[] toArray() { return Arrays.copyOf(elementData, size); }
public <T> T[] toArray(T[] a) { if (a.length < size) return (T[]) Arrays.copyOf(elementData, size, a.getClass()); System.arraycopy(elementData, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
能夠認爲是Iterator的升級版,繼承自Iterator,並且多了一些操做函數
public interface ListIterator<E> extends Iterator<E> { boolean hasNext();//是否有下一元素 E next();//下一元素 boolean hasPrevious();//是否有前一元素 E previous();//前一元素 int nextIndex();//下一個元素索引 int previousIndex();//前一個元素索引 void remove();//移除 void set(E e);//設置 void add(E e);//添加 }
public ListIterator<E> listIterator() { return new ListItr(0); } public ListIterator<E> listIterator(int index) { rangeCheckForAdd(index); return new ListItr(index); }
private class ListItr extends Itr implements ListIterator<E> { ListItr(int index) {//構造函數傳入索引值 super(); cursor = index;//遊標處於索引位 } public boolean hasPrevious() { return cursor != 0;//遊標不爲0說明有前元素 } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } @SuppressWarnings("unchecked") public E previous() { checkForComodification(); //索引爲遊標-1 int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); //elementData儲存當前數組 Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i;//遊標-1 return (E) elementData[lastRet = i];//返回元素 } public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { //設置最後返回的那個元素索引 ArrayList.this.set(lastRet, e); } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; //在最後返回的那個元素索引處添加元素 ArrayList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } }
就醬紫,ArrayList還有個SubList沒有接觸過,暫時就不看了源碼分析
項目源碼 | 日期 | 備註 |
---|---|---|
V0.1--無 | 2018-10-2 | Java容器源碼攻堅戰--第二戰:ArrayList |
V0.2--無 | - | - |
筆名 | 微信 | 愛好 | |
---|---|---|---|
張風捷特烈 | 1981462002 | zdl1994328 | 語言 |
個人github | 個人簡書 | 個人CSDN | 我的網站 |
1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3---我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持測試