ArrayList 源码分析

首先看下ArrayList的关系图

ArrayList 继承自AbstractList,实现了List 、RandomAccess、Cloneable、Serializable接口
点开List接口,你会发现我们常用的方法基本上都在这里,当然,实现都是在ArrayList当中。

再回到ArrayList的源码,我们会发现ArrayList的几大特点:

  • ArrayList维护了一个动态的数组,可以增加或缩减其长度。
  • ArrayList 是线性不安全的,在多线程中操作一个ArrayList需要手动保证数据的同步。
  • 每个ArrayList实例维护了一个capacity的属性,顾名思义,就是集合的容量,且其值会随着数据的变化增长或者衰减。

ArrayList的两大精华

  • 扩容
  • Iterator

首先看下这几个属性

/**
 * 默认的容器大小
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 *一个空的数组
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 在这里要清楚transient 的含义,被该属性修饰的变量不会被序列化
 */
transient Object[] elementData;

/**
 * 元素长度
 *
 */
private int size;

//这个属性来自AbstrctList  代表的含义是每当ArrayList的结构发生变化的时候 该变量+1;该属性同样使用了transient 修饰,因为没必要持久化。
protected transient int modCount = 0;

大精华之一:扩容:

最常见的add()方法

/**
 * Appends the specified element to the end of this list.
 *
 * @param e element to be appended to this list
 * @return true (as specified by {@link Collection#add})
 */
public boolean add(E e) {
    //扩容
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    //赋值
    elementData[size++] = e;
    return true;
}

/**
 * Increases the capacity of this ArrayList instance, if
 * necessary, to ensure that it can hold at least the number of elements
 * specified by the minimum capacity argument.
 *
 * @param   minCapacity   the desired minimum capacity
 */
public void ensureCapacity(int minCapacity) {
    //最小长度 如果数组不为空 最小即为0 否则为默认的10
    int minExpand = (elementData != EMPTY_ELEMENTDATA)
        // any size if real element table
        ? 0
        // larger than default for empty table. It's already supposed to be
        // at default size.
        : DEFAULT_CAPACITY;
    //如果需要的长度  即目标长度大于最小长度 说明需要扩容
    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

private void ensureCapacityInternal(int minCapacity) {
    //如果数组为空 最小容量取下面二者最大值
    if (elementData == EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {

    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

/**
 * Increases the capacity to ensure that it can hold at least the
 * number of elements specified by the minimum capacity argument.
 *
 * @param minCapacity the desired minimum capacity
 */

//重点来了 此乃精华之一: 扩容
private void grow(int minCapacity) {
    // overflow-conscious code
    //旧集合的长度
    int oldCapacity = elementData.length;
    //新集合的长度 是旧集合长度的 大概1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

//附带下copy方法  
public static  T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}


public static  T[] copyOf(U[] original, int newLength, Class newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}


其实扩容也就在grow()方法中的几行代码 主要是对集合长度的控制。

大精华之二 Iterator:
最常见的listIterator()方法

 /**
 * Returns a list iterator over the elements in this list (in proper
 * sequence), starting at the specified position in the list.
 * The specified index indicates the first element that would be
 * returned by an initial call to {@link ListIterator#next next}.
 * An initial call to {@link ListIterator#previous previous} would
 * return the element with the specified index minus one.
 *
 * 

The returned list iterator is fail-fast. * * @throws IndexOutOfBoundsException {@inheritDoc} */ public ListIterator listIterator() { return listIterator(0); } public ListIterator listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index); }

ListItr是个什么鬼?原来是一个内部类,实现了ListIterator接口

private class ListItr extends Itr implements ListIterator {
    //把坐标传递进来
    ListItr(int index) {
        cursor = index;
    }

    public boolean hasPrevious() {
        return cursor != 0;
    }

    public E previous() {
        checkForComodification();
        try {
            int i = cursor - 1;
            E previous = get(i);
            lastRet = cursor = i;
            return previous;
        } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
        }
    }

    public int nextIndex() {
        return cursor;
    }

    public int previousIndex() {
        return cursor-1;
    }

    public void set(E e) {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();

        try {
            AbstractList.this.set(lastRet, e);
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }

    public void add(E e) {
        checkForComodification();

        try {
            int i = cursor;
            AbstractList.this.add(i, e);
            lastRet = -1;
            cursor = i + 1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
}

//看完之后你会发现确实没什么东西 但是Iterator这个东西在很多地方都有用到,这里就显现出来接口的强大之处。

总结

看完ArrayList的源码之后,对ArrayList数据存储有了更深的理解,然而它的性能如何呢,要知道扩容和写数据都是需要时间的,经过测试,ArrayList在遍历和普通插入(add(object))的性能上都优于LinkedList。但是LinkedList在首尾进行操作的性能上明显优于ArrayList.

你可能感兴趣的:(Android,安卓,java,List,ArrayList)