扩容机制:当数组容量不够时,ArrayList 会创建一个新的更大的数组(通常是原来大小的1.5倍),然后将旧数组中的元素复制到新数组中。
以下是源码分析
创建 ArrayList 的默认容量是 10。
如果我们不给定扩容参数的话,它会默认传递 size+1,也就是重载函数 grow()。容量要进行扩容,那就要确定扩容的大小,newCapacity 就是计算的大小,但是这个大小需要进一步的判断,因为扩容太大容易导致溢出。所以这个问题就交给了 ArraysSupport. newLength 函数来解决,它传递的参数是:oldCapacity (原来的容量)、minCapacity - oldCapacity(最小扩容减去原来的容量也就是 1)、oldCapacity>>1 (原来的容量的一半)
这里 minCapacity - oldCapacity 的默认是 1,但程序员是可以传递 minCapacity 的。
那我们进入到 newLength 函数中看看它是怎么判断的。首先 ArraysSupport 类中先定义了最大容量 SOFT_MAX_ARRAY_LENGTH = Integer.Max_Value - 8。然后 newLength 方法中会对新的容量进行计算。
int prefLength = oldLength + Math.max(minGrowth, prefGrowth);
确认了新容量之后,就要进行判断容量是否溢出。没有溢出就进行扩容,如果溢出,还要调用 hugeLength 方法。
这里是 hungeLength 方法,传递的是原来的容量和最小扩容大小(默认是 1,程序员可以传递任意大小)。
方法中先对 oldLength 和 minGrowth 进行相加,判断是否小于 0(也就是判断是否溢出),如果溢出了就直接抛异常了。没有溢出的话直接给定最大容量了。
总结以下 ArrayList 的扩容机制,默认大小是 10,默认 1.5 倍扩容,当然程序员可以指定扩容量。如果进行扩容的时候溢出了,那么就直接扩容到最大容量 Integer. Max_Value - 8,为什么要-8?
在 JVM 中,所有对象(包括数组)都有一个对象头,用于存储一些元数据信息。对于数组来说,对象头包含数组的长度等信息。对象头的大小根据 JVM 的具体实现可能有所不同,但通常为 8 到 16 字节。