ArrayList源码解析
ArrayList扩容机制
示例代码如下:
package com.itshijie.collectionanalyse;
import java.util.ArrayList;
public class ArrayListSoruceAnalyse {
public static void main(String[] args) {
// 1. Collections -- List -- ArrayList
// 无参构造创建arrayList
ArrayList<Integer> arrayList = new ArrayList();
int n = 100;
for (int i = 1; i < n;i++){
arrayList.add(i);
}
}
}
ArrayList()
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
transient Object[] elementData; // non-private to simplify nested class access
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
无参构造创建对象,elementData用于存放数据的容器,默认为一个空容器
Object[]数组来存储
首先进行了自动装箱,将int --> Integer类型的数据
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
package com.itshijie.collectionanalyse;
import java.util.ArrayList;
public class ArrayListSoruceAnalyse {
public static void main(String[] args) {
// 1. Collections -- List -- ArrayList
// 有参构造创建arrayList
ArrayList<Integer> arrayList = new ArrayList(10);
int n = 100;
for (int i = 1; i < n;i++){
arrayList.add(i);
}
}
}
ArrayList(int initialCapacity)
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) { //如果给定的容量>0,那么设置数组大小为指定大小
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) { //如果给定的容量为0,设置数组大小为EMPTY_ELEMENTDATA,空数组
// private static final Object[] EMPTY_ELEMENTDATA = {};
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 如果指定的容量大小不合法,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
add(E e)
// 执行添加操作
public boolean add(E e) {
// 确保内部容量足以存放该数据
ensureCapacityInternal(size + 1); // Increments modCount!! private int size; 0
elementData[size++] = e; //添加元素,并对size++,size记录的是当前数组的大小,也就是当前数组中拥有的元素个数
return true; //返回true表示添加成功
}
ensureCapacityInternal
// 完成操作需要的最小容量minCapacity,minCapacity = size+1 ,size初始化为0,因此默认最小容量至少为1,也就是要想将数据放入到集合中,此时至少需要1个单元的空间
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
calculateCapacity
// 计算minCapacity最小容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
// 如果elementData 为 DEFAULTCAPACITY_EMPTY_ELEMENTDATA,无参构造就是该值
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
// 返回DEFAULT_CAPACITY 和 minCapacity中的最大值,此时minCapacity为1,因此会返回DEFAULT_CAPACITY = 10
return Math.max(DEFAULT_CAPACITY , minCapacity);
}
return minCapacity;
}
ensureExplicitCapacity
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //当发生添加的时候,modCount就加1 ,记录改变容器次数,添加数据就会使容器发生一些改变,因此modCount++
// overflow-conscious code
// 如果 minCapacity > elementData.length,如果此时需要的最小容量已经大于了数组的长度,那么就应该对数组进行扩容了
// private static final int DEFAULT_CAPACITY = 10; 经过计算我们的数组大小为10
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xoNoqJXG-1686569529019)(E:\zy-o\Vue\image-20230222110123625.png)]
当minCapacity - elementData.length > 0 时会进行扩容操作,因此具体的扩容操作是在grow中完成的
grow
private void grow(int minCapacity) { //将当前所需最小容量传入进来,此时为11
// overflow-conscious code
int oldCapacity = elementData.length; //旧容量,此时为数组的长度,10
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:
// 最后调用Arrays.copyOf,将原数组中的数据复制到新数组,并设置了扩容后的容量
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;
}
总结
1) 通过无参构造创建ArrayList,首先设置elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA,此值为一个空的数组,首次进行添加时,会进入add方法,首先执行了ensureCapacityInternal(size + 1),来确保当前容器还能够存放下数组,此方法体中首先调用了calculateCapacity,根据传递的elementData和minCapacity来计算出最终的minCapacity并返回(使用无参构造计算出的minCapacity为DEFAULT_CAPACITY,为10),接着调用ensureExplicitCapacity,该方法判断了当前容器是否能存放,如果能存放,那么无操作,记录modCount++,如果所需容量>数组现在的容量,会进行扩容操作,具体执行了grow方法,扩容机制扩容为原来的容量的1.5倍。如果扩容后的容量还是不能满足所需最小容量,那么就会将扩容后的容量重新置为所需最小容量,最后将minCapacity来返回。
2)通过有参构造创建ArrayList,例如传入的initCapacity为10,如果给定的容量>0,那么设置数组大小为指定大小,如果给定的容量为0,那么设置elementData为EMPTY_ELEMENTDATA,一个空数组,如果给定容量<0,会抛出相应的异常,接着就与上述一直执行add操作。