本篇主要对添加元素,和扩容机制进行分析
属性
/**
* 序列号
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认初始容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
*
* 共享的空数组用于实例空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 共享的空数组用于实例化默认大小的空数组,用于区分EMPTY_ELEMENTDATA,
* 当添加了第一元素的,数组容量扩充为DEFAULT_CAPACITY,即10。
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 存储数据的数组,
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* 当前元素个数
*/
private int size;
构造方法
// 参数:initialCapacity 指定大小初始化容量
public ArrayList(int initialCapacity) {
// 初始化容量>0
if (initialCapacity > 0) {
// new Object[initialCapacity],创建指定大小的数组,并赋值给elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
// 如果initialCapacity 为0,则把EMPTY_ELEMENTDATA这个空数组,赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
} else {
// 如果initialCapacity<0,抛出异常
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* 无参构造,DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给elementData
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) {
// Collection转换为数组,并赋值给 elementData
elementData = c.toArray();
// 如果元素个数不为0
if ((size = elementData.length) != 0) {
// 如果c.toArray不是Object类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// 如果为0,用EMPTY_ELEMENTDATA替换,赋值给elementData
this.elementData = EMPTY_ELEMENTDATA;
}
}
- ArrayList():在放入第一个元素的时候,扩容到默认大小10;
- ArrayList(int initialCapacity):创建一个initialCapacity大小的数组给elementData
- ArrayList(Collection<? extends E> c):将Collection类型的集合转换为数组,赋值给elementData
add(E e)
我们来看看整个add(E e)的过程
public boolean add(E e) {
// 确认容量
ensureCapacityInternal(size + 1); // Increments modCount!!
//赋值
elementData[size++] = e;
return true;
}
-------------------------------------------------------
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
/**
* 这里就是为甚么 new ArrayList()默认为10 的原因
* 用无参构造函数进行初始化的时候:
* 把DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给了elementData
* 在第一次添加元素时进入到这里
* 经过max计算minCapacity=10;
* 然后调用ensureExplicitCapacity扩容到10,
*
*/
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
//确认是否进行扩容
ensureExplicitCapacity(minCapacity);
}
-------------------------------------------------------
private void ensureExplicitCapacity(int minCapacity) {
// modCount:记录操作次数,modCount++;
modCount++;
// overflow-conscious code
// 如果最小的容量-当前数组长度>0
if (minCapacity - elementData.length > 0)
// 扩容
grow(minCapacity);
}
-------------------------------------------------------
private void grow(int minCapacity) {
// overflow-conscious code
// oldCapacity 原来容量;
int oldCapacity = elementData.length;
// 新的容量 = 原来容量+原来容量/2;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新的容量-最小容量<0
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);
}
ArrayList添加元素操作,就这么个流程,先确认是否扩容,然后在放入元素
- 如果使用new ArrayList()创建对象,第一个元素的时候,扩容到默认大小10;
- 如果是其他情况,则当size+1-elementData.length>0时(当前元素个数+1-当前容量>0),进行扩容
扩容方式:
新的容量 = 原来容量+原来容量/2: int newCapacity = oldCapacity + (oldCapacity >> 1)
这里用到了位运算:可以参考我的另外一篇文章:位运算
add(int index, E element)
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
//这个arraycopy是native方法,大该意思大家还是能看出来;index后面的元素
// 通通后移一位
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
//插入元素
elementData[index] = element;
size++;
}