ArrayList
- 构造函数
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static final int DEFAULT_CAPACITY = 10;
private static final Object[] EMPTY_ELEMENTDATA = {};
transient Object[] elementData;
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);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
this.elementData = EMPTY_ELEMENTDATA;
}
}
我们先来看构造函数,ArrayList.java里面有几个变量,
final MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
设置最大数组大小,其中 Integer.MAX_VALUE
为 java 中 int最大值 为的 2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647,所以这里的值为 2147489647 - 8=214748363 9;
final DEFAULT_CAPACITY = 10
默认大小为10
final Object[] EMPTY_ELEMENTDATA = {}
设置一个空的object对象数组
transient Object[] elementData
声明一个新的 Object 不被序列化的数组,这个数组是主要数组,所有的元素都将放在这个数组里面
当我们调用无参的构造函数时,初始化当前elementData
为EMPTY_ELEMENTDATA
,即为空。
当我们调用有初始化大小的构造函数时,判断initialCapacity
是否大于零,大于则初始化一个大小为
initialCapacity
的Object对象数组。等于零则初始化当前elementData
为EMPTY_ELEMENTDATA
,即为空
当小于零,抛出错误
当我们调用参数为集合的构造函数时,此构造函数的意思是将集合转为ArrayList,
先将 参数转为数组并赋给elementData
,判断当elementData
长度不为零时,判断是否成功将参数集合转化为Object类型的数组,如果转化成Object类型的数组成功,则将数组进行复制,转化为Object类型的数组。
当 elementData
长度为零时,则初始化当前elementData
为EMPTY_ELEMENTDATA
,即为空。
- 扩容
public boolean add(E e) {
ensureCapacityInternal(size + 1); //扩容
...
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
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++;//记录修改次数
// overflow-conscious code
if (minCapacity - elementData.length > 0)//判断大小是否大于当前list对象的长度
grow(minCapacity);//长度增加
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;//未增加前长度
int newCapacity = oldCapacity + (oldCapacity >> 1);//位运算,让长度增加原来的1.5倍
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);//复制扩容并令当前对象等于它
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow溢出
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
//当长度大于最大长度,则返回int类最大值,否则返回最大长度
//源码上有写最大长度=int类最大值-8
}
扩容函数为add()
函数调用,函数主体是ensureCapacityInternal
,参数为未扩容前大小+1,
调用 ensureCapacityInternal(int minCapacity)
函数后,
再调用 calculateCapacity(Object[] elementData, int minCapacity)
,这个函数有两个参数,一个是当前elementData,一个是扩容后的大小 ,这个函数的作用是,判断elementData
是否为空,如果是,则返回默认大小和扩容后大小的最大值,如果不为空,则直接返回扩容后的大小
然后调用ensureExplicitCapacity()
这个函数的参数是 校验后的 minCapacity
,这个函数的作用是,开始先将修改步骤++,即 modCount++
,然后执行grow()
进行扩容,
minCapacity
表示集合为了确保添加元素成功的最小容量。在扩容的时候,首先将原元素数组的长度增大1.5倍(oldCapacity + (oldCapacity >> 1))
,然后对扩容后的容量与minCapacity
进行比较:① 新容量小于minCapacity
,则将新容量设为minCapacity
;②新容量大于minCapacity
,则指定新容量。最后将旧数组拷贝到扩容后的新数组中。
资料:
copyOf详解
modCount
transient