ArrayList源碼分析

ArrayList源碼解析(基於安卓JDK)

一、 ArrayList概述:

ArrayList是基於數組實現的,是一個動態數組,其容量能自動增長,類似於C語言中的動態申請內存,動態增長內存。

ArrayList不是線程安全的,只能用在單線程環境下,多線程環境下可以考慮用Collections.synchronizedList(List l)函數返回一個線程安全的ArrayList類,也可以使用concurrent併發包下的CopyOnWriteArrayList類。

位置:package java.util

1)實現接口 :
Cloneable, Serializable, RandomAccess
>
ArrayList實現了Serializable接口,因此它支持序列化,能夠通過序列化傳輸,實現了RandomAccess接口,支持快速隨機訪問,實際上就是通過下標序號進行快速訪問,實現了Cloneable接口,能被克隆。可以接受泛型。
>

2)繼承類 :
AbstractLis

AbstractList 繼承自 AbstractCollection 抽象類,實現了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父類。

它實現了 List 的一些位置相關操作(比如 get,set,add,remove),是第一個實現隨機訪問方法的集合類,但不支持添加和替換。

在 AbstractCollection 抽象類 中我們知道,AbstractCollection 要求子類必須實現兩個方法: iterator() 和 size()。 AbstractList 實現了 iterator()方法:

public Iterator<E> iterator() {
    return new Itr();
}

ArrayList類的定義:

public class ArrayListextends AbstractList
implements Cloneable, Serializable, RandomAccess

>

每個ArrayList實例都有一個容量(在Android裏的ArrayList的初始值爲12 JDK1.71爲10),該容量是指用來存儲列表元素的數組的大小。它總是至少等於列表的大小。隨着向ArrayList中不斷添加元素,其容量也自動增長。自動增長會帶來數據向新數組的重新拷貝,因此,如果可預知數據量的多少,可在構造ArrayList時指定其容量。在添加大量元素前,應用程序也可以使用ensureCapacity操作來增加ArrayList實例的容量,這可以減少遞增式再分配的數量。

注意,此實現不是同步的。如果多個線程同時訪問一個ArrayList實例,而其中至少一個線程從結構上修改了列表,那麼它必須保持外部同步。

 List list = Collections.synchronizedList(new ArrayList(...));

二、 ArrayList的實現:

對於ArrayList而言,它實現List接口、底層使用數組保存所有元素。其操作基本上是對數組的操作。下面我們來分析ArrayList的源代碼:

1) 私有屬性

ArrayList定義只定義類3個屬性:

1、定義一個Object類型的數組。

/**
 * The elements in this list, followed by nulls.
 */
transient Object[] array;

有個關鍵字需要解釋:transient。

Java的serialization提供了一種持久化對象實例的機制。當持久化對象時,可能有一個特殊的對象數據成員,我們不想用serialization機制來保存它。爲了在一個特定對象的一個域上關閉serialization,可以在這個域前加上關鍵字transient。
有點抽象,看個例子應該能明白。

 public class UserInfo implements Serializable {  
 private static final long serialVersionUID = 996890129747019948L;  
 private String name;  
 private transient String psw;  

 public UserInfo(String name, String psw) {  
     this.name = name;  
     this.psw = psw;  
 }  

 public String toString() {  
     return "name=" + name + ", psw=" + psw;  
 }  
 }  

 public class TestTransient {  
 public static void main(String[] args) {  
     UserInfo userInfo = new UserInfo("張三", "123456");  
     System.out.println(userInfo);  
     try {  
         // 序列化,被設置爲transient的屬性沒有被序列化  
         ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(  
                 "UserInfo.out"));  
         o.writeObject(userInfo);  
         o.close();  
     } catch (Exception e) {  
         // TODO: handle exception  
         e.printStackTrace();  
     }  
     try {  
         // 重新讀取內容  
         ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
                 "UserInfo.out"));  
         UserInfo readUserInfo = (UserInfo) in.readObject();  
         //讀取後psw的內容爲null  
         System.out.println(readUserInfo.toString());  
     } catch (Exception e) {  
         // TODO: handle exception  
         e.printStackTrace();  
     }  
 }  
}

被標記爲transient的屬性在對象被序列化的時候不會被保存。

接着回到ArrayList的分析中……

2、記錄數組的長度。 很容易理解,array存儲ArrayList內的元素,size表示它包含的元素的數量。

int size;

3、在創建ArrayList對象時,會默認初始化集合的大小,那麼接下來這個靜態常量就是來定義初始化的集合的長度。前面已經說過:。隨着向ArrayList中不斷添加元素,其容量也自動增長。那麼默認的List集合的長度就是通過該變量定義的。

/**
 * The minimum amount by which the capacity of an ArrayList will increase.
 * This tuning parameter controls a time-space tradeoff. This value (12)
 * gives empirically good results and is arguably consistent with the
 * RI's specified default initial capacity of 10: instead of 10, we start
 * with 0 (sans allocation) and jump to 12.
 */
private static final int MIN_CAPACITY_INCREMENT = 12;

2) 構造方法

ArrayList提供了三種方式的構造器,

  1. 可以構造一個默認初始容量爲12的空列表、

    public ArrayList() {
        array = EmptyArray.OBJECT;
    }
    
  2. 構造一個指定初始容量的空列表

    public ArrayList(int capacity) {
    if (capacity < 0) {
        throw new IllegalArgumentException("capacity < 0: " + capacity);
    }
    array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
    }
    
  3. 以及構造一個包含指定collection的元素的列表,這些元素按照該collection的迭代器返回它們的順序排列的。

    public ArrayList(Collection<? extends E> collection) {
    if (collection == null) {
        throw new NullPointerException("collection == null");
    }
    
    Object[] a = collection.toArray();
    if (a.getClass() != Object[].class) {
        Object[] newArray = new Object[a.length];
        System.arraycopy(a, 0, newArray, 0, a.length);
        a = newArray;
    }
    array = a;
    size = a.length;
    }
    

裏面的一個方法需要說明以下:

/** 
* src  : 需要拷貝的數組
* Pos:從src的那個下標開始拷貝
* dst:將src的內容拷貝到的數組。
* dstPos:congsrcPos的那個下標開始放置被拷貝的元素
* length:拷貝的元素的個數
*/
public static native void arraycopy(Object src, int srcPos,
    Object dst, int dstPos, int length);

ArrayList提供了set(int index, E element)、add(E e)、add(int index, E element)、addAll(Collection

3) 元素存儲:

這裏有個很有意思的知識點

    int [] b = new int[10];
    int [] a= b;
    a[2] = 33;
    System.out.println(b[2]);

最後輸出 33(問了別人發現數組是引用類型,a改變了,b也會跟着改變)

我以前都不知道爲什麼add方法中最後都沒有給array賦值?

1. add(E object)

將指定的元素添加到此列表的尾部。 先判斷是否有剩餘的空間存放該元素。如果沒有聲譽的空間則將新創建一個集合newArray,並將大小擴大爲原來的1.5被。然後將array裏面的數據拷貝到newArray裏面。

/**
 * Adds the specified object at the end of this {@code ArrayList}.
 *
 * @param object
 *            the object to add.
 * @return always true
 */
@Override public boolean add(E object) {
    Object[] a = array;
    int s = size;
    if (s == a.length) {  //存儲滿了,數組長度等於集合大小,需要申請空間
    //s的長度是否小於6
    //s的長度小於6 新的數組的長度爲s+6,反之,s=1.5*s (s>>1 s向右移一位)

        Object[] newArray = new Object[s +
                (s < (MIN_CAPACITY_INCREMENT / 2) ? 
                 MIN_CAPACITY_INCREMENT : s >> 1)]; 
        System.arraycopy(a, 0, newArray, 0, s);
        array = a = newArray;
    }
    a[s] = object;
    size = s + 1;  //添加完成size+1
    modCount++;     //迭代器需要用到的參數
    return true;    //添加成功返回true
}

有些問題需要注意下
(1)
位運算

(2)位運算——左移右移運算詳解

常見應用
左移相當於*2,只是要注意邊界問題。如char a = 65; a<<1 按照*2來算爲130;但有符號char的取值範圍-128~127,已經越界,多超出了3個數值,所以從-128算起的第三個數值-126纔是a<<1的正確結果。
而右移相當於除以2,只是要注意移位比較多的時候結果會趨近去一個非常小的數,如上面結果中的-1,0。

(3)modCount( 從 java.util.AbstractList 裏面繼承的元素)

protected transient int modCount

已從結構上修改 此列表的次數。從結構上修改是指更改列表的大小,或者以其他方式打亂列表,使正在進行的迭代產生錯誤的結果。

此字段由 iterator 和 listIterator 方法返回的迭代器和列表迭代器實現來使用。如果意外更改了此字段中的值,則迭代器(或列表迭代器)將拋出 ConcurrentModificationException 來響應 next、remove、previous、set 或 add 操作。在迭代期間面臨併發修改時,它提供了快速失敗 行爲,而不是非確定性行爲。

子類是否使用此字段是可選的。如果子類希望提供快速失敗迭代器(和列表迭代器),則它只需在其 add(int, Object) 和 remove(int) 方法(以及它所重寫的、導致列表結構上修改的任何其他方法)中增加此字段。對 add(int, Object) 或 remove(int) 的單個調用向此字段添加的數量不得超過 1,否則迭代器(和列表迭代器)將拋出虛假的 ConcurrentModificationExceptions。如果某個實現不希望提供快速失敗迭代器,則可以忽略此字段。 

2. add(int index, E object)

將指定的元素插入此列表中的指定位置。向右移動當前位於該位置的元素(如果有)以及所有後續元素(將其索引加 1)。

指定者:
    接口 List<E> 中的 add
覆蓋:
    類 AbstractList<E> 中的 add
參數:
    index - 指定元素所插入位置的索引。
    element - 要插入的元素。 
拋出:
    IndexOutOfBoundsException - 如果索引超出範圍 (index < 0 || index > size())。
//源碼中的Add方法
@Override public void add(int index, E object) {
    Object[] a = array;
    int s = size;
    //添加指定的下標超出size,直接拋出下標越界異常
    if (index > s || index < 0) {
        throwIndexOutOfBoundsException(index, s);
    }

    if (s < a.length) {
        //複製把a中index後面的元素複製到a中不過index後的元素下標+1
        /*
        *
        *    a 數組a,  index 第一個數組從什麼地方開始(是包括下標爲index的元素),index+1, 第二個數組從什麼,地方開始 s-index 複製幾個元素  
        *    
        */
        System.arraycopy(a, index, a, index + 1, s - index);
    } else {
        //進行擴容,原理和上面的add是一樣的,newCapacity(s)是擴容方法

        // assert s == a.length;
        Object[] newArray = new Object[newCapacity(s)];
        //把a中從0到index-1複製帶newArray裏面
        //數組拷貝,先拷貝0~index -1的數據。(共index個數據)
        System.arraycopy(a, 0, newArray, 0, index);
        //把a中從 index 到 s 複製帶newArray裏面的 index+ 到s+1
        //在拷貝index以後的數據。注意新的數組的index的數據是空的。
        System.arraycopy(a, index, newArray, index + 1, s - index);
        //將新的數組賦值給array
        array = a = newArray;
    }
    a[index] = object;
    size = s + 1;
    modCount++;
}

添加的方法如下圖
添加

3 擴容方法 newCapacity

ArrayList是基於數組實現的,屬性中也看到了數組,數組的長度是不可變的,那添加有可能超出數組容量,如果數組容量不夠了呢?下面的方法就是擴容

 /**
 * This method controls the growth of ArrayList capacities.  It represents
 * a time-space tradeoff: we don't want to grow lists too frequently
 * (which wastes time and fragments storage), but we don't want to waste
 * too much space in unused excess capacity.
 *
 * NOTE: This method is inlined into {@link #add(Object)} for performance.
 * If you change the method, change it there too!
 * 
 * @pram currentCapacity 是數組長度,判斷當currentCapacity小於6則新數組大小爲
 * currentCapacity + 6否則爲 currentCapacity + 0.5*currentCapacity
 */
private static int newCapacity(int currentCapacity) {
    int increment = (currentCapacity < (MIN_CAPACITY_INCREMENT / 2) ?
            MIN_CAPACITY_INCREMENT : currentCapacity >> 1);
    return currentCapacity + increment;
}

4 addAll(Collection

4) 越界異常:

這裏專門建立一個方法來拋出下標越界異常

/**
 * This method was extracted to encourage VM to inline callers.
 * TODO: when we have a VM that can actually inline, move the test in here too!
 */
static IndexOutOfBoundsException throwIndexOutOfBoundsException(int index, int size) {
    throw new IndexOutOfBoundsException("Invalid index " + index + ", size is " + size);
}

5) 清空元素

(1)clear()

清空元素
移除此列表中的所有元素。此調用返回後,列表將爲空。

/**
* Removes all elements from this {@code ArrayList}, leaving it empty.
*
* @see #isEmpty
* @see #size
*/
@Override public void clear() {
if (size != 0) {
Arrays.fill(array, 0, size, null);
size = 0;
//不知道爲什 modCount++
modCount++;
}
}

這裏面的Arrays.fill()方法爲

/** 
*
將指定的 Object 引用分配給指定 Object 數組指定範圍中的每個元素。填充的範圍從索引 fromIndex(包括)一直到索引 toIndex(不包括)。(如果 fromIndex==toIndex,則填充範圍爲空。)

參數:
    array - 要填充的數組。
    start - 要使用指定值填充的第一個元素的索引(包括)。
    end - 要使用指定值填充的最後一個元素的索引(不包括)。
    value - 要存儲在數組的所有元素中的值。 
拋出:
    IllegalArgumentException - 如果 fromIndex > toIndex 
    ArrayIndexOutOfBoundsException - 如果 fromIndex < 0 或 toIndex > a.lengt

*/
public static void fill(Object[] array, int start, int end, Object value) {
    //這個方法就是檢查下是否下標越界
    Arrays.checkStartAndEnd(array.length, start, end);
    for (int i = start; i < end; i++) {
        array[i] = value;
    }
}

public static void checkStartAndEnd(int len, int start, int end) {
    if (start < 0 || end > len) {
        throw new ArrayIndexOutOfBoundsException("start < 0 || end > len."
                + " start=" + start + ", end=" + end + ", len=" + len);
    }
    if (start > end) {
        throw new IllegalArgumentException("start > end: " + start + " > " + end);
    }
}

克隆clone()

返回此 ArrayList 實例的淺表複製。(不復制這些元素本身。) 就是返回一個克隆體

調整數組容量

調整數組容量
public void ensureCapacity(int minCapacity)

如有必要,增加此 ArrayList 實例的容量,以確保它至少能夠容納最小容量參數所指定的元素數。

參數:
minCapacity - 所需的最小容量。

public void ensureCapacity(int minimumCapacity) {
    Object[] a = array;
    if (a.length < minimumCapacity) {//考慮的非常周全
        Object[] newArray = new Object[minimumCapacity];
        System.arraycopy(a, 0, newArray, 0, size);
        array = newArray;
        modCount++;
    }
}

5)獲取元素

(1)get(int index)

非常簡單直接返回對應下標的元素即可

@SuppressWarnings("unchecked") @Override public E get(int index) {
    if (index >= size) {
        throwIndexOutOfBoundsException(index, size);
    }
    return (E) array[index];
}

6)兩個簡單方法

返回長度
 @Override public int size() {
    return size;
}
返回是否爲空
@Override public boolean isEmpty() {
    return size == 0;
}

7)是否包含contains(Object object)

如果此列表中包含指定的元素,則返回 true。

指定者:
    接口 Collection<E> 中的 contains
指定者:
    接口 List<E> 中的 contains
覆蓋:
    類 AbstractCollection<E> 中的 contains

參數:
    object - 測試此列表中是否存在的元素。 可以是null
返回:
    如果指定的元素存在,則返回 true;否則返回 false。


@Override public boolean contains(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = 0; i < s; i++) {
            if (object.equals(a[i])) {
                return true;
            }
        }
    } else {
        for (int i = 0; i < s; i++) {
            if (a[i] == null) {
                return true;
            }
        }
    }
    return false;
}

8)搜索

這裏的兩個方法都是查找參數的,沒查到就返回 -1

(1)indexOf(Object object)搜索給定參數第一次出現的位置,使用 equals 方法進行相等性測試。

這裏面使用equals方法來判斷的,說以判斷時可以重寫equals方法來自定義相等條件
 @Override public int indexOf(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = 0; i < s; i++) {
            if (object.equals(a[i])) {
                return i;
            }
        }
    } else {
        for (int i = 0; i < s; i++) {
            if (a[i] == null) {
                return i;
            }
        }
    }
    return -1;
}

(2)lastIndexOf(Object object)返回指定的對象在列表中最後一次出現的位置索引。

@Override public int lastIndexOf(Object object) {
    Object[] a = array;
    if (object != null) {
        for (int i = size - 1; i >= 0; i--) {
            if (object.equals(a[i])) {
                return i;
            }
        }
    } else {
        for (int i = size - 1; i >= 0; i--) {
            if (a[i] == null) {
                return i;
            }
        }
    }
    return -1;
}

9)刪除元素

刪除操作,就是把數組吧要刪除的元素後面的所有元素向前平移,再把最後的元素置爲null

3個刪除方法

(1)remove(int index) 只刪除一個

移除此列表中指定位置上的元素。向左移動所有後續元素(將其索引減 1)。

指定者:
    接口 List<E> 中的 remove
覆蓋:
    類 AbstractList<E> 中的 remove

參數:
    index - 要移除的元素的索引。 
返回:
    從列表中移除的元素。 
拋出:
    IndexOutOfBoundsException - 如果索引超出範圍 (index < 0 || index >= size())。

這個方法在Collection裏面是沒有的

@Override public E remove(int index) {
    Object[] a = array;
    int s = size;
    if (index >= s) {
        throwIndexOutOfBoundsException(index, s);
    }
    @SuppressWarnings("unchecked") E result = (E) a[index];
    System.arraycopy(a, index + 1, a, index, --s - index);
    a[s] = null;  // Prevent memory leak
    size = s;
    modCount++;
    return result;
}

(2)remove(Object object) 只刪除一個

從此列表中移除指定元素的單個實例(如果存在),此操作是可選的。更正式地說,如果列表包含一個或多個滿足 (o==null ? e==null : o.equals(e)) 的元素 e,則移除該元素。如果列表中包含指定的元素,則返回 true(或者等同於這種情況:如果列表隨調用的結果而發生改變,則返回 true)。

指定者:
    接口 Collection<E> 中的 remove
指定者:
    接口 List<E> 中的 remove
覆蓋:
    類 AbstractCollection<E> 中的 remove

參數:
    o - 要從此列表中移除的元素(如果存在)。 
返回:
    如果此列表包含指定的元素,則返回 true。

@Override public boolean remove(Object object) {
    Object[] a = array;
    int s = size;
    if (object != null) {
        for (int i = 0; i < s; i++) {
            if (object.equals(a[i])) {
                System.arraycopy(a, i + 1, a, i, --s - i);
                a[s] = null;  // Prevent memory leak
                size = s;
                modCount++;
                return true;
            }
        }
    } else {
        for (int i = 0; i < s; i++) {
            if (a[i] == null) {
                System.arraycopy(a, i + 1, a, i, --s - i);
                a[s] = null;  // Prevent memory leak
                size = s;
                modCount++;
                return true;
            }
        }
    }
    return false;
}

(3)removeRange(int fromIndex, int toIndex) 可移除多個

移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之間的所有元素。向左移動所有後續元素(減小其索引)。此調用將列表縮短了 (toIndex - fromIndex) 個元素。(如果 toIndex==fromIndex,則此操作無效。)

覆蓋:
    類 AbstractList<E> 中的 removeRange

參數:
    fromIndex - 要移除的首個元素的索引。
    toIndex - 最後一個要移除的元素後面那個元素的索引。

 @Override protected void removeRange(int fromIndex, int toIndex) {
    if (fromIndex == toIndex) {
        return;
    }
    Object[] a = array;
    int s = size;
    if (fromIndex >= s) {
        throw new IndexOutOfBoundsException("fromIndex " + fromIndex
                + " >= size " + size);
    }
    if (toIndex > s) {
        throw new IndexOutOfBoundsException("toIndex " + toIndex
                + " > size " + size);
    }
    if (fromIndex > toIndex) {
        throw new IndexOutOfBoundsException("fromIndex " + fromIndex
                + " > toIndex " + toIndex);
    }

    System.arraycopy(a, toIndex, a, fromIndex, s - toIndex);
    int rangeSize = toIndex - fromIndex;
    Arrays.fill(a, s - rangeSize, s, null);
    size = s - rangeSize;
    modCount++;
}

10)改

set方法,比add方法要簡單,直接賦值就行

public E set(int index,
E element)

用指定的元素替代此列表中指定位置上的元素。

指定者:
    接口 List<E> 中的 set
覆蓋:
    類 AbstractList<E> 中的 set

參數:
    index - 要替代的元素的索引。
    element - 存儲在指定位置上的元素。 
返回:
    以前位於該指定位置上的元素。 
拋出:
    IndexOutOfBoundsException - 如果索引超出範圍 (index < 0 || index >= size())。

@Override public E set(int index, E object) {
    Object[] a = array;
    if (index >= size) {
        throwIndexOutOfBoundsException(index, size);
    }
    @SuppressWarnings("unchecked") E result = (E) a[index];
    a[index] = object;
    return result;
}

11)剩下的方法

(1) toArray()

返回一個按照正確的順序包含此列表中所有元素的數組。(就是獲取數組)

指定者:
    接口 Collection<E> 中的 toArray
指定者:
    接口 List<E> 中的 toArray
覆蓋:
    類 AbstractCollection<E> 中的 toArray

返回:
    以正確的順序包含此列表中所有元素的數組。
另請參見:
    Arrays.asList(Object[])


@Override public Object[] toArray() {
    int s = size;
    Object[] result = new Object[s];
    System.arraycopy(array, 0, result, 0, s);
    return result;
}

(2) toArray(T[] contents)

這個方法比較燒腦

返回一個按照正確的順序包含此列表中所有元素的數組;返回數組的運行時類型就是指定數組的運行時類型。如果列表能放入指定的數組,則返回放入此列表元素的數組。否則,將根據指定數組的運行時類型和此列表的大小分配一個新的數組。

如果指定的數組能容納列表並有剩餘空間(即數組的元素比列表的多),那麼會將數組中緊跟在集合末尾的元素設置爲 null。這對確定列表的長度很有用,但只 在調用方知道列表中不包含任何 null 元素時纔有用。

指定者:
    接口 Collection<E> 中的 toArray
指定者:
    接口 List<E> 中的 toArray
覆蓋:
    類 AbstractCollection<E> 中的 toArray

參數:
    a - 要存儲列表元素的數組,如果它足夠大的話;否則,它是一個爲存儲列表元素而分配的、具有相同運行時類型的新數組。 
返回:
    包含列表元素的數組。 
拋出:
    ArrayStoreException - 如果 a 的運行時類型不是此列表中每個元素的運行時類型的超類型。

@Override public <T> T[] toArray(T[] contents) {
    int s = size;
    if (contents.length < s) {
        @SuppressWarnings("unchecked") T[] newArray
            = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
        contents = newArray;
    }
    System.arraycopy(this.array, 0, contents, 0, s);
    if (contents.length > s) {
        contents[s] = null;
    }
    return contents;
}

Array.newInstance

創建一個具有指定的組件類型和長度的新數組。調用此方法等效於創建如下數組:

     int[] x = {length};
     Array.newInstance(componentType, x);


參數:
    componentType - 表示新數組的組件類型的 Class 對象
    length - 新數組的長度 
返回:
    新數組 
拋出:
    NullPointerException - 如果指定的 componentType 參數爲 null 
    IllegalArgumentException - 如果 componentType 爲 Void.TYPE 
    NegativeArraySizeException - 如果指定的 size 爲負

    public static Object newInstance(Class<?> componentType, int size) throws NegativeArraySizeException {
    if (!componentType.isPrimitive()) {
        return createObjectArray(componentType, size);
    } else if (componentType == char.class) {
        return new char[size];
    } else if (componentType == int.class) {
        return new int[size];
    } else if (componentType == byte.class) {
        return new byte[size];
    } else if (componentType == boolean.class) {
        return new boolean[size];
    } else if (componentType == short.class) {
        return new short[size];
    } else if (componentType == long.class) {
        return new long[size];
    } else if (componentType == float.class) {
        return new float[size];
    } else if (componentType == double.class) {
        return new double[size];
    } else if (componentType == void.class) {
        throw new IllegalArgumentException("Can't allocate an array of void");
    }
    throw new AssertionError();
}

public boolean isPrimitive() {
  return primitiveType != 0;
}

(3) trimToSize()

將此 ArrayList 實例的容量調整爲列表的當前大小。應用程序可以使用此操作來最小化 ArrayList 實例的存儲量。
public void trimToSize() {
int s = size;
if (s == array.length) {
return;
}
if (s == 0) {
array = EmptyArray.OBJECT;
} else {
Object[] newArray = new Object[s];
System.arraycopy(array, 0, newArray, 0, s);
array = newArray;
}
modCount++;
}

(4)iterator()

返回在此 collection 的元素上進行迭代的迭代器。

指定者:
    接口 Iterable<E> 中的 iterator

返回:
    在此 collection 的元素上進行迭代的 Iterator

 @Override public Iterator<E> iterator() {
    return new ArrayListIterator();//內部類
}

(5) hashCode()

返回此列表的哈希碼值。

此實現準確使用在 List.hashCode 方法的文檔中用於定義列表哈希函數的代碼。

指定者:
    接口 Collection<E> 中的 hashCode
指定者:
    接口 List<E> 中的 hashCode
覆蓋:
    類 Object 中的 hashCode

返回:
    此列表的哈希碼值。
另請參見:
    Object.equals(java.lang.Object), Hashtable



@Override public int hashCode() {
    Object[] a = array;
    int hashCode = 1;
    for (int i = 0, s = size; i < s; i++) {
        Object e = a[i];
        hashCode = 31 * hashCode + (e == null ? 0 : e.hashCode());
    }
    return hashCode;
}

(6) equals(Object o)

將指定的對象與此列表進行相等性比較。當且僅當指定的對象也是一個列表,兩個列表具有相同的大小,而且兩個列表中所有相應的元素對都相等 時,才返回 true。(如果 (e1==null ? e2==null :e1.equals(e2)),則元素 e1 和 e2 相等。)換句話說,如果兩個列表包含相同的元素,且元素的順序也相同,纔將它們定義爲相等。

此實現首先檢查指定的對象是否爲此列表。如果是,則返回 true;否則,它將檢查指定的對象是否爲一個列表。如果不是,它將返回 false;如果是,它將迭代兩個列表,比較相應的元素對。如果有任何比較結果返回 false,則此方法將返回 false。如果某中某個迭代器在另一迭代器之前完全迭代元素,則會返回 false(因爲列表是不等長的);否則,在迭代完成時將返回 true。

指定者:
    接口 Collection<E> 中的 equals
指定者:
    接口 List<E> 中的 equals
覆蓋:
    類 Object 中的 equals

參數:
    o - 與此列表進行相等性比較的對象。 
返回:
    如果指定對象與此列表相等,則返回 true。

(7) private static final long serialVersionUID = 8683452581122892189L;
>
/**
功能:serialVersionUID是用來驗證版本一致性的字段。我們將一個類的二進制字節序列轉爲java對象,也就是反序列化時,JVM會把傳進來的二進制字節流中的serialVersionUID和本地相應的實體或對象的serialVersionUID進行比較,如果相同,則認爲兩個類是一致的,可以進行反序列化,否則就會出現版本不一致的反序列化異常。
*
*/

(8) writeObject(ObjectOutputStream stream)

//輸出流

(9)readObject(ObjectInputStream stream)

//輸入流

12) 內部類ArrayListIterator

內部迭代器(不知道是不是Android裏面纔有)

private class ArrayListIterator implements Iterator<E> {
    /** Number of elements remaining in this iteration */
    private int remaining = size;

    /** Index of element that remove() would remove, or -1 if no such elt */
    private int removalIndex = -1;

    /** The expected modCount value */
    private int expectedModCount = modCount;

    //hasNext()和next()是結合起來使用的

    public boolean hasNext() {
        return remaining != 0;
    }

    @SuppressWarnings("unchecked") public E next() {
        ArrayList<E> ourList = ArrayList.this;
        int rem = remaining;
        if (ourList.modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        if (rem == 0) {
            throw new NoSuchElementException();
        }
        remaining = rem - 1;
        return (E) ourList.array[removalIndex = ourList.size - rem];
    }

    public void remove() {
        Object[] a = array;
        int removalIdx = removalIndex;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        if (removalIdx < 0) {
            throw new IllegalStateException();
        }
        System.arraycopy(a, removalIdx + 1, a, removalIdx, remaining);
        a[--size] = null;  // Prevent memory leak
        removalIndex = -1;
        expectedModCount = ++modCount;
    }
}

參考文章 https://www.2cto.com/kf/201604/502504.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章