ArrayList源码分析

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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值