ArrayList的扩容时机和扩容方式
大家好! 最近看了一下JAVA集合的相关底层实现原理,这里简单对 ArrayList的扩容机制 做一下简单介绍。本文是个人的简单理解,希望对大家有一定的帮助。
ArrayList扩容机制简单介绍
这里我简单介绍扩容机制的主要实现部分,对于一些理解能力很好的朋友,可以直接看这部分,后面的可以忽略:
- 扩容时机 ,ArrayList的扩容时机,主要看它底层的方法;
private void ensureExplicitCapacity(int minCapacity) {
modCount++; // 标记集合修改的次数
// 主要在这也行代码
/**
* @minCapacity 添加元素后,集合的最小的容量
* @elementData.length 实现集合的数组的长度
*/
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
主要判断所需的长度大小是否小于数组的长度,如果数组的长度比所需要的小,那么久进行扩容;
- 扩容方式, 在判断需要扩容的情况下,对数组进行扩容,下面来介绍扩容的主要代码;
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 这是扩容的核心代码
/**
* oldCapacity >> 1 :表示数组的原来长度进行 除2操作
* 例如:oldCapacity = elementData.length = 10
* 二进制表示为:1010,向右以为后:0101 = 5
* 总的来说:就是把原来的数组长度 *1.5
*/
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
这就是扩容方式的主要代码,但是,我个人觉得,实际上并不是按照1.5倍扩容,而是按照 位运算算出来的, oldCapacity + (oldCapacity >> 1),或者可以说是 1.5倍后向下取整;例如:原来的长度为15,1111 + 0111 = 22;扩容后的数组长度应该为22。
ArrayList扩容机制详细介绍
这部分是对上一部分做一个详细的介绍,如何在上面的部分,你已经看懂了,那么这部分你可不用在花时间看了。
- 扩容时机
扩容时机的话,我们主要从add方法入手,最后判断是否扩容是在ensureExplicitCapacity()方法,下面一个个看:
/**
* 添加元素到集合的末尾
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
// 这里的 minCapacity = size + 1
// 可以理解为,如果要添加这个元素,集合需要的大小
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
// 主要判断 集合需要的最小的大小,如何是初始化,则为10,反之则为 size + 1
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
// 这里 判断是否需要扩容
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// 底层数组的长度>集合需要的最小大小 ?扩容:不扩容
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
大家可以在ensureExplicitCapacity方法中看到,是否需要扩容的判断 if (minCapacity - elementData.length > 0)
总结:当添加元素后的集合大小(这个大小是理论上的,实际上还没有添加元素),比底层实现集合的数组的长度大的话,就进行扩容;
2. 扩容方式
扩容方式,主要分析grow这个方法
private void grow(int minCapacity) {
// 获取原来数组的长度
int oldCapacity = elementData.length;
// 数组长度变为原来的 1.5 倍(乘1.5倍后向下取整)
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 扩容的大小 是否 还是小于 最小的集合大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 这里判断的是,扩容是否 比 2 的30次还大
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 创建一个扩容后的新数组,并对新数组进行元素赋值
elementData = Arrays.copyOf(elementData, newCapacity);
}
以上就是我对ArrayList源码查看,然后得出的一些结论,希望对大家有帮助,如果有错误,希望大家指出,我及时修改,以免误导大家。最后,大家在学习的时候,也可以通过DEBUG的方式,一遍遍跑源码,这样也会让自己对知识点理解更加深刻,不会说看完就忘。