【Java系列】ArrayList源码解析

温馨提示:本文源码分析基于JDK 1.8。

目录

ArrayList简介

ArrayList 核心源码分析

底层数据结构

构造函数

自动扩容

add 方法

grow方法


ArrayList简介

ArrayList 实现了 List 接口,是有序集合,即用户可以精确控制每个元素在列表中的插入位置,允许放入 null 元素,底层通过数组实现,支持动态扩容。每个 ArrayList 都有一个容量(capacity),表示底层数组的实际大小。当向容器中添加元素时,如果容量不足,容器会自动增大底层数组的大小。

先来看一张 ArrayList 的类图:

【Java系列】ArrayList源码解析_第1张图片

ArrayList 继承 AbstractList,实现了 List,RandomAccess,Cloneable,java.io.Serializable这些接口。

  • List:提供添加、删除、查找等操作,并且可以通过下标进行访问。
  • RandomAccess:提供 快速随机访问 能力。
  • Cloneable:表明它具有拷贝能力,可以进行深拷贝或浅拷贝操作。
  • Serializable:表明它可以被序列化操作,也就是将对象转化为字节流进行网络传输,非常方便。

ArrayList 核心源码分析

底层数据结构

这里的数组是一个Object数组,以便能够容纳任何类型的对象。

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 */
transient Object[] elementData; // non-private to simplify nested class access

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

构造函数

可以看到:以无参构造创建 ArrayList 时,会初始化赋值为一个空数组。当真正对 ArrayList 添加元素时,才会真正分配容量,数组容量默认扩充为 10。在下面自动扩容章节会详细介绍。

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
    }
}

/**
 * Constructs an empty list with an initial capacity of ten.
 */
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *
 * @param c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

自动扩容

这里以无参构造函数创建的 ArrayList 为例分析。

add 方法

可以看到,检查是否需要扩容是通过 ensureCapacityInternal(int minCapacity) 来实现的。 

/**
 * 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!!
    // 无参构造的list添加第一个元素时,size++ 说明索引下标是0,list size大小是1
    elementData[size++] = e;
    return true;
}

而真正实现扩容是 grow(int minCapacity) 方法。

private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

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

grow方法

/**
 * 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;
    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);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍左右(oldCapacity 为偶数就是 1.5 倍, 否则是 1.5 倍左右)!比如:10 + 10/2 = 15,33 + 33/2 = 49,奇数会丢掉小数部分。

">>"(移位运算符):>>1 右移一位相当于除 2,右移 n 位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了 1 位,所以相当于 oldCapacity / 2。采用位运算,主要是为了提高效率,节省资源。

通过例子详细解读一下 grow() 方法:

  • add 添加第 1 个元素时,oldCapacity 为 0,经比较后第一个 if 判断成立,newCapacity = minCapacity (为10)。但是第二个 if 判断不会成立,即无参构造的 ArrayList 添加第 1 个元素后,数组容量变为 10,ArrayList size 增加为 1。
  • add 添加第 11 个元素进入 grow 时,oldCapacity=10,newCapacity=15,minCapacity=11,第一个 if 判断不成立,第二个 if 判断也不成立。所以数组容量扩容为 15,ArrayList size 增加为 11。
  • 以此类推......

你可能感兴趣的:(Java,源码系列,java)