源码解析之--ArrayList

ArrayList应该是Java日常开发中使用频率最高的集合类型之一(还有HashMap),虽然我们经常使用它,但大多数人可能都不太清楚它的实现原理和运行机制

从这篇文章中我们能学到什么:
1. ArrayList的内部定义(包括数据结构,实现接口)
2. ArrayList的最小最大容量
3. ArrayList的扩容原理
4. ArrayList的序列化方式
下面我们一起从ArrayList的源代码层面去解析吧

ArrayList内部实现

类的定义

// AbstractList中声明了List该有的一些方法,同时实现了迭代器
// ArrayList具有随机访问、克隆以及序列化的能力
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable,java.io.Serializable

数据结构

// ArrayList内部实现就是这个数组,其length就是ArrayList的capacity
// transient关键字意味着elementData将不会序列化,那么ArrayList又将如何序列化?
transient Object[] elementData;

new ArrayList<>()方法

// 这里说明new ArrayList<>()时,ArrayList是空的,capacity为0
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList的容量
// ArrayList的默认的容量大小是10
private static final int DEFAULT_CAPACITY = 10;
// 空list
private static final Object[] EMPTY_ELEMENTDATA = {};
// 创建ArrayList实例时,如果未提供capacity,那ArrayList内部将会是这个数组,其capacity是0,然后在add第一个元素的时候进行扩容。
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

// ArrayList的最大容量是Integer.MAX_VALUE - 8,减8的原因是因为一些虚拟机在数组中有预留位保存头部信息
/**
 * The maximum size of array to allocate.
 * Some VMs reserve some header words in an array.
 * Attempts to allocate larger arrays may result in
 * OutOfMemoryError: Requested array size exceeds VM limit
 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
ArrayList的扩容校验

add方法

// add首先会就行容量校验
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

ensureCapacityInternal方法

// 当elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,会将list的capacity设置为Math.max(DEFAULT_CAPACITY, minCapacity),所以capacity至少会是10
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity)
    }

    ensureExplicitCapacity(minCapacity);
}
ArrayList扩容
// 至少会扩容 1/2 oldCapacity(向下取整)
// 如果newCapacity小于最少需要的容量minCapacity,那newCapacity=minCapacity
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);
}

// 取MAX_ARRAY_SIZE或者抛出OutOfMemoryError异常
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

// 该方法中调用了grow方法,即当前需要的容量要比当前ArrayList的capacity大时进行扩容
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

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

为什么ArrayList会采用这两个方法来完成序列化与反序列化,见Java集合序列化

private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }
总结

回答一下上面的几点问题:

1、ArrayList内部如何实现?适合什么样的操作场景?

数组实现,适合查询频繁的场景,不适合非尾部的增删操作;实现了AbstractList,迭代器,还具有具有随机访问、克隆以及序列化的能力

2、new ArrayList<>()方法调用后所提供的ArrayList容量是多大?

答案是0,从上面可以看出是调用了add方法后才有的容量,且至少为10

3、ArrayList什么时候扩容?如何扩容?扩多大?

当前需要的容量要比当前ArrayList的capacity大时进行扩容;扩容的操作是重新分配数组;至少会扩容 1/2 oldCapacity(向下取整),如果newCapacity小于最少需要的容量minCapacity,那将扩大至最少需要容量。

4、ArrayList如何序列化?

通过readObject和writeObject,详见集合序列化

5、ArrayList最大容量是多大?

Integer.MAX_VALUE - 8,部分虚拟机在数组中预留了8位存储头部信息。

6、如果要看Vector和ArrayList,LinkedList的区别

请移步http://blog.csdn.net/qq_28260521/article/details/78707400

如果您觉得我的文章帮到了您,请下方评论个1,您的支持是我最大的动力

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

keyboy_rl

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

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

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

打赏作者

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

抵扣说明:

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

余额充值