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提供了三種方式的構造器,
可以構造一個默認初始容量爲12的空列表、
public ArrayList() { array = EmptyArray.OBJECT; }
構造一個指定初始容量的空列表
public ArrayList(int capacity) { if (capacity < 0) { throw new IllegalArgumentException("capacity < 0: " + capacity); } array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]); }
以及構造一個包含指定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,只是要注意邊界問題。如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;
}
}