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;
}
}