ArrayList扩容机制

List的主要实现类,底层使用Object[]存储,适用于频繁的查找工作,线程不安全。

特点:

1.增删慢:每次删除元素,都需要更改数组长度、拷贝以及移动元素位置;

2.查询快:由于数组在内存中是一块连续空间,因此可以根据地址+索引的方式快速获取对应位置上的元素。

【数据结构】ArrayList底层是数组队列,相当于动态数组。

 源码分析:

①成员变量:

private static final int DEFAULT_CAPACITY = 10;// 默认的初始容量是10
// 空元素数组
private static final Object[] EMPTY_ELEMENTDATA = {};
// 默认容量的空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 存储元素的数组 
transient Object[] elementData;
// 集合容量
private int size;

②构造方法:

// 1.构造一个初始容量的空数组。
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
// 2.构造具有指定初始容量的数组。
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);
    }
}
//3.构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序
public ArrayList(Collection<? extends E> c) {
    // 将集合构造中的集合对象转成数组
    Object[] a = c.toArray();
    if ((size = a.length) != 0) {
        if (c.getClass() == ArrayList.class) {
            // 类型为ArrayList则直接赋值
            elementData = a;
        } else {
            //如果不一样,使用Arrays的copyOf方法进行元素的拷贝
            elementData = Arrays.copyOf(a, size, Object[].class);
        }
    } else {
        // replace with empty array.
        elementData = EMPTY_ELEMENTDATA;
    }
}

③扩容源码:

// 添加一个元素
public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true; 
}

// 1.主体函数
private void ensureCapacityInternal(int minCapacity) {
    // 对容量进行判断
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}


// 2.通过最小容量和默认容量求出较大值 (主要用于第一次扩容:如果是无参构造方式创建的数组对象,第一次添加元素的时候扩容到大小为10)
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;
}

// 3.判断是否需要进行扩容
private void ensureExplicitCapacity(int minCapacity) {
    // 实际修改集合次数+1 (在扩容的过程中没用,主要是用于迭代器中)
    modCount++;
    // 判断当前最小容量是否大于数组长度
    if (minCapacity - elementData.length > 0)
        // 将计算出来的容量传递给核心扩容方法
        grow(minCapacity);
}



// 4.核心扩容方法
private void grow(int minCapacity) {
    // 记录数组的实际长度
    int oldCapacity = elementData.length;
    // 核心扩容算法,原容量的1.5倍
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    // 判断新容量是否小于当前最小容量(第一次调用add方法必然小于)
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    
    // 判断新容量是否大于最大数组长度,如果
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        
        // 条件满足就计算出一个超大容量
        newCapacity = hugeCapacity(minCapacity);

    // 调用数组工具类方法,创建一个新数组,将新数组的地址赋值给elementData
    elementData = Arrays.copyOf(elementData, newCapacity);
}

总结:

初始容量:创建ArrayList对象时,会分配一个初始容量,默认为10。
增长因子:每次扩容时,ArrayList会根据增长因子来计算新的容量。默认情况下,增长因子为1.5,即每次扩容后容量变为原来的1.5倍。
扩容触发条件:当ArrayList的size超过当前容量时,就会触发扩容操作。
扩容策略:ArrayList在扩容时,会创建一个新的更大容量的数组,并将原有元素复制到新数组中。

具体的扩容流程如下:

当向ArrayList添加元素时,会先检查当前容量是否足够。如果不足,则进行扩容操作。
扩容时,根据增长因子计算新的容量,并创建一个新的数组。
将原有数组中的元素复制到新数组中。
更新ArrayList内部的引用,指向新数组。
添加新元素到新数组中。

 

 

 

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值