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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

申小东001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值