点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。
本文在公众号文章已同步,还有各种一线大厂面试原题、我的学习系列笔记。
arraylist每次添加元素时都会检查是否需要扩容:arraylist第一次添加元素时,赋予arraylist默认容量10,再往里面添加元素(所以arraylist默认容量10并不是初始化的时候赋予的,而是无参构造第一次添加元素的时候赋予的);以后每次添加元素前先检查当前元素个数是否已经达到容量上限,若是则先以1.5倍*原容量上限进行扩容再添加元素,如下:
- arraylist中的初始变量
//当首次创建arraylist是无参构造,即没有指定初始容量时,赋予该默认数组给arraylist
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
//当首次创建arraylist是有参构造,即指定了初始容量,但初始容量指定为0时,赋予该默认数组给arraylist
private static final Object[] EMPTY_ELEMENTDATA = {};
//用于arraylist中实际存放元素的数组,注意此变量是transient修饰的,不参与序列化
transient Object[] elementData;
//数组元素的实际个数,默认0;不同于elementData.length,elementData.length是数组长度
private int size;
- arraylist的三个构造函数
(1)默认无参构造:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
(2)指定了长度的有参构造
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];//指定长度>0,直接赋予指定长度的数组
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;//指定长度为0,赋予默认的长度为0的数组
} else {
throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
}
}
(3)指定了数组元素的有参构造
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
- arraylist添加元素,两种方法
//把元素添加到数组尾部
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 检查是否需要扩容,size为当前实际元素个数,size+1为添加元素后需要的实际最小空间;第一次添加元素时size为0,传入1
elementData[size++] = e;//检查完再往里面添加元素
return true;
}
//把元素添加到数组特定的下标处
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // 检查是否需要扩容
System.arraycopy(elementData, index, elementData, index + 1,size - index);//检查完先拷贝元素:把元素后移
elementData[index] = element;//再添加元素
size++;
}
- 检查是否需要扩容
private void ensureCapacityInternal(int minCapacity){
//calculateCapacity()获取添加元素后所需的最小数组容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
//获取添加元素后所需的最小数组容量
private static int calculateCapacity(Object[] elementData, int minCapacity) {
//调用的无参构造初始化arraylist,且是第一次添加元素,返回10,即设置‘添加元素后所需的最小数组容量’为10:minCapacity=1,elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA,DEFAULT_CAPACITY为10
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
//其他情况:调用有参构造初始化arraylist且第一次添加元素或非第一次添加元素,则‘添加元素后所需的最小数组容量’为添加元素后实际元素个数
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;//用于快速失败机制
//当前数组长度=elementData.length < minCapacity='添加元素后所需的最小数组容量',则需要扩容
//(1)无参构造第一次添加元素时:10>0,需扩容,传入10;(2)无参构造添加元素后所需的最小数组容量为11时:11>10,需扩容,传入11;...
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //扩容1.5倍:oldCapacity>>1即oldCapacity/2=0.5*oldCapacity
if (newCapacity - minCapacity < 0)
//无参构造第一次添加元素时会走这一步:oldCapacity=newCapacity=0,minCapacity=10
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
//扩容后新容量newCapacity>MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8时
newCapacity = hugeCapacity(minCapacity);
//(1)无参构造第一次添加元素时elementData为空数组,newCapacity=10
elementData = Arrays.copyOf(elementData, newCapacity);
}
OK,如果文章哪里有错误或不足,欢迎各位留言。
创作不易,各位的「三连」是二少创作的最大动力!我们下期见!