ArrayList源码分析

来源:互联网 发布:mac 安装apache 编辑:程序博客网 时间:2024/06/06 05:16

1, 结构图

ArrayList 是android中很常见的一种数据结构,经常用,现在就来分析一下源码吧,结构图如下,


其继承结构从上往下论述。

1.1, Iterable  Iterator

这两个都是接口,实现他们的方法就可以对集合进行遍历

public interface Iterable<T> {    Iterator<T> iterator();}
public interface Iterator<E> {  public boolean hasNext();  public E next();  public void remove();}

2.2, Collection  AbstractCollection

Collection 接口共有15个方法,其中iterator从Iterable 继承而来。如下,


AbstractCollection是一个抽象类,继承了Collection,实现了部分方法。

2.3, List  AbstractList

List只是一个接口,提供一些方法, AbstractList实现了部分方法。list中的方法如下,


2, ArrayList分析

首先看看ArrayList的构造方法

2.1, 构造方法

ArrayList一共有三个构造方法,从最简单的开始分析,

public ArrayList() {        array = EmptyArray.OBJECT;    }

Array定义如下,

transient Object[] array;

transient关键字是啥意思?

在序列化对象时,在array前面加上transient关键字是不会进行系列化的。

那么 EmptyArray.OBJECT又是什么呢?

在EmptyArray中的定义如下,

public static final Object[] OBJECT = new Object[0];

原来构造了一个大小为0 的Object数组。

 

第二个构造方法也挺简单, 构造了一个大小为capacity 的Object数组。

public ArrayList(int capacity) {        if (capacity < 0) {            throw new IllegalArgumentException("capacity < 0: " + capacity);        }        array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);}
第三个构造方法将其他集合转化为ArrayList

2.2, add方法

Add有四个方法,

1,在array的最后添加一个元素

2,在任一位置添加一个元素

3,在array的最后添加一个集合(Collection)

4, 在任一位置添加一个集合

这4个方法的本质是一样的,以第一种为例来论述,

@Override public boolean add(E object) {        Object[] a = array;        int s = size;        if (s == a.length) {            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;        modCount++;        return true;    }
private static final int MIN_CAPACITY_INCREMENT = 12;

array最开始是大小为0的数组,是怎么添加元素的呢?

Array. Length 表示的是实际申请的数组大小,而size表示Array中已使用的数组大小。并且数组的大小翻倍申请的,太过频繁申请会影响效率。所以,使用的时候一定是size方法而不是Length方法。

 

Remove 有2种方法,

1,删除任一位置的元素

2,删除特定的元素。

 

get (intindex) 得到指定位置的元素

size()数组的大小

isEmpty() 判断array中的元素是否为空,

注意: 不要使用array. Length为0来判断。

Contains(Object object) array数组中是否包含对象

indexOf(Object object) 返回对象最开始出现的位置

lastIndexOf(Object object) 返回对象最后出现的位置

trimToSize() 将array数组简单整理

hashCode()array数组的哈希码

set(int index, E object)将第index的元素替换为object

3, 接口实现

3.1, Iterable  Iterator

继承Iterable 只是表面的,主要是继承Iterator

 

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

ArrayListIterator是什么?是ArrayList的内部类并且实现了对应的方法,这样就可以使用iterator方法来进行循环了。

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

3.2, Cloneable

继承了Cloneable接口,就必须实现clone方法,这样该类才可以进行clone。但是,

Cloneable接口中没有任何方法?这不符合一般的逻辑啊!

Java有一个特性,就是所有的java类都继承自Object

类,而clone方法是在Object类中定义的,其定义如下,

protected Object clone() throws CloneNotSupportedException {        if (!(this instanceof Cloneable)) {            throw new CloneNotSupportedException("Class " + getClass().getName() +                                                 " doesn't implement Cloneable");        }        return internalClone();    }

原来是这样的, Cloneable只是调用clone方法的一个声明。

1,要想调用Object类的clone方法,必须继承Cloneable接口

2,继承了Cloneable接口不一定非要实现clone方法。

问题:复制在其他地方论述。

3.3, RandomAccess

RandomAccess接口里也没有什么方法,也只是一个标记,标志着什么呢?

直接看ArrayList的equals方法,

@Override public boolean equals(Object o) {        if (o == this) {            return true;        }        if (!(o instanceof List)) {            return false;        }        List<?> that = (List<?>) o;        int s = size;        if (that.size() != s) {            return false;        }        Object[] a = array;        if (that instanceof RandomAccess) {            for (int i = 0; i < s; i++) {                Object eThis = a[i];                Object ethat = that.get(i);                if (eThis == null ? ethat != null : !eThis.equals(ethat)) {                    return false;                }            }        } else {  // Argument list is not random access; use its iterator            Iterator<?> it = that.iterator();            for (int i = 0; i < s; i++) {                Object eThis = a[i];                Object eThat = it.next();                if (eThis == null ? eThat != null : !eThis.equals(eThat)) {                    return false;                }            }        }        return true;    }

从上面的代码中可以看出,如果一个集合继承了RandomAccess接口,那么必然会有get方法,就可以使用其get方法来获取元素,否则只能用iterator。那么可以这样理解,集合类如何继承了RandomAccess接口,那么必然会有一个get方法。

问题: get方法和 iterator 哪一个的效率更高呢?

Equals方法是判断两个集合中的每个元素是不是完全相同。

3.4 Serializable

Serializable简单说就是保存对象的实例变量状态,并且可以将保存的状态读取出来。

Serializable接口也没有任何方法,除了继承之外,还要有一个哈希码,直接看源码

private static final long serialVersionUID = 8683452581122892189L;    private void writeObject(ObjectOutputStream stream) throws IOException {        stream.defaultWriteObject();        stream.writeInt(array.length);        for (int i = 0; i < size; i++) {            stream.writeObject(array[i]);        }    }    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {        stream.defaultReadObject();        int cap = stream.readInt();        if (cap < size) {            throw new InvalidObjectException(                    "Capacity: " + cap + " < size: " + size);        }        array = (cap == 0 ? EmptyArray.OBJECT : new Object[cap]);        for (int i = 0; i < size; i++) {            array[i] = stream.readObject();        }    }

由此看到,进行系列化和反系列化时,只是简单仅针对array数组值。

问题: Serializable 和 Parcelable 的区别。

4, 横向比较

从源码中看, Vector和ArrayList很像,都是继承AbstractList等,那么他们之间有哪些区别呢?

1, Vector有些方法使用关键字synchronized进行修饰,所以Vector是线程安全的,导致Vector在效率上低于ArrayList。

2,都是采用线性连续空间存储元素,当空间不足时,2个类增加方法是不同的。

ArrayList一次可以增长自身空间的一半,而Vector可以设置增长因子。

 

现在一般很少使用Vector了。

Stack继承Vector,只是多了几个方法而已,



























0 0