ArrayList源码分析

29 阅读3分钟

前言

本文通过ArrayList源码,来分析ArrayList自动扩容的实现原理,以下代码均为ArrayList源码,注释是博主加上的。


一、创建ArrayList对象

创建集合时,会在底层创建一个默认长度为0的数组,涉及到的源码如下:

private static final Object[] EMPTY_ELEMENTDATA = {};

transient Object[] elementData;

// 当创建一个ArrayList对象时,会调用ArrayList的空参构造,创建一个长度为0的数组
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

二、添加元素

添加第一个元素,使用add(E)时,底层会创建一个新的长度为10的数组。涉及的源码如下:

// size是数组的长度,创建对象时后集合长度为0
private int size;

// 默认容量
private static final int DEFAULT_CAPACITY = 10;

// 设置数组最大长度为,int类型的最大整数 - 8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

public boolean add(E e) {
    modCount++;
    // 调用重载方法add(),e是添加的这个元素;elementData是创建ArrayList对象时长度为0的空数组;size是欲存入元素的索引,开始为0
    add(e, elementData, size);
    return true;
}

private void add(E e, Object[] elementData, int s) {
    // 将数组长度和欲存入元素的索引比较 首次存入时 0 == 0 为true
    if (s == elementData.length)
        // 扩容数组
        elementData = grow();
    // 如果不相等,说明数组容量还有空余,将元素存入数组,索引+1
    elementData[s] = e;
    size = s + 1;
}

private Object[] grow() {
    // size + 1是目前数组所需要的最小容量
    return grow(size + 1);
}

private Object[] grow(int minCapacity) {
    // 拷贝数组, 将扩容后的数组再赋值给原数组, elementData是原数组;扩容后的数组长度调用了newCapacity()方法,传入的参数是目前所需的最小容量
    return elementData = Arrays.copyOf(elementData, newCapacity(minCapacity));
}

private int newCapacity(int minCapacity) {
    // 老数组的长度
    int oldCapacity = elementData.length;
    // 新数组,即扩容的数组长度 = 原数组的长度 + 原数组长度的1/2
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 如果新数组 - 目前所需要的最小容量 <= 0;首次添加元素时,结果为true
    if (newCapacity - minCapacity <= 0) {
        // 如果老数组为空数组,也即首次添加元素
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            // 返回DEFAULT_CAPACITY,即返回10,数组扩容成长度为10的数组
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        // 如果目前所需的最小容量小于0,报错
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        
        // 如果扩容到原数组的1.5倍后,仍不够,就返回目前所需要的最小容量。即新数组的容量 = 老数组容量 + 所需的容量
        return minCapacity;
    }
    
    // 如果扩容到原数组的1.5倍后,够用。扩增的容量不超过设定的最大值,则返回前面设定的扩容方案,即扩容到原来数组的1.5倍。
    return (newCapacity - MAX_ARRAY_SIZE <= 0)
        ? newCapacity
        // 如果扩增的容量超过了设定的最大值,执行hugeCapacity(minCapacity)方法
        : hugeCapacity(minCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    // 如果扩增的容量超过了设定的最大值,即Intege.MAX_VALUE - 8,则把扩容的数组长度限定为Intege.MAX_VALUE
    return (minCapacity > MAX_ARRAY_SIZE)
        ? Integer.MAX_VALUE
        : MAX_ARRAY_SIZE;
}

分析后,可知ArrayList集合底层的扩容原理

3、数组存满时,会扩容1.5倍

4、如果一次添加多个元素,1.5倍还放不下,则新创建数组的长度以实际为准

另外,通过分析源码可知:集合的长度,最大不能超过Integer.MAX_VALUE;

首次发布

hezhongying.blog.csdn.net/article/det…