ArrayList基本构成以及动态扩容机制
一.静态Filed和实例Filed解析
1.private static final int DEFAULT_CAPACITY = 10**(线程共享,默认容量)**:初始化默认值为10,默认容量,用于动态扩容。
2.private static final Object[] EMPTY_ELEMENTDATA = {}(线程共享,类存在的属性):共享的空对象数组,未指定容量,类自身存在的属性,是所有实例共享的。
3.private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
注:类 的 Field 指的 默认的容量_空的_元素数据 Object[] 数组引用 ,是指定了容量,但是为空的实例;
4.transient Object[] elementData (实例属性,线程不共享): transient 标识 数据在 Serializable(序列化的)会被忽略 真实值 ,
从而初始化 成默认值 基本数据类型 默认 0 ,引用类型默认null。
5.private int size :指定实例所保存元素的个数
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
private static final long serialVersionUID = 8683452581122892189L;//UUID 序列化时唯一标识
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;//默认容量
/**
* Shared empty array instance used for empty instances.
*/
private static final Object[] EMPTY_ELEMENTDATA = {};//所有未指定容量的空实例的共同指向的实例
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//定义了容量但是元素个数为空的实例共同指向的实例
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
//transient: 代表当对象序列化的时候,不被序列化,这个Field 是用来分配每个实例存储元素的空间
/**
* The size of the ArrayList (the number of elements it contains).
*
* @serial
*/
private int size;
//记录当前元素的个数
二.构造方法设计
1.带有一个参数 initialCapacity 初始化容量:
当选择 initialCapacity == 0 ,存放元素的 elementData 会使用 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 指定的空间,也就是初始化 EMPTY_ELEMENTDATA
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {//当指定了初始容量时,直接创建数组初始化elementData
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;//等于零时,当作没有容量但是为空的实例处理 指向EMPTY_ELEMENTDATA
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
2.无参构造器: 直接 使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA 初始化 elementData
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;//DEFAULTCAPACITY_EMPTY_ELEMENTDATA未指定容量,实例数据为空
}
3.带有一个Collection<? extents E> 引用 参数 的构造方法 :
Collection<? extends E> c:声明接口类型,在运行时确定真实类型
public ArrayList(Collection<? extends E> c) {
Object[] a = c.toArray(); // 将对应的集合类型的值转换 成数组类型
if ((size = a.length) != 0) { // 初始化 size值
if (c.getClass() == ArrayList.class) { // 因为 ArrayList 也是 Collection的一个实现类 ,所以判断当前实例类型是否是ArraList类型,如果是c.toArray() 采用的就是ArrayList重写的toArray方法 已经完成了 类型检验 ,所以可以忽略对a的类型检验
elementData = a; //如果是,可以直接 将 a 作为elementData 的初始化值
} else {
elementData = Arrays.copyOf(a, size, Object[].class); //否则要通过 对a进行类型检验
}
} else {
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;//让当前引用指向同一为空的数组,所有空实例共享的
}
}
三.由构造方法引出动态扩容机制
1.AraayList 的Add()方法构成:
1.add(E e)
public boolean add(E e) {
ensureCapacityInternal(size + 1); //增加一个元素,先进行内部容量确定
elementData[size++] = e;
return true;
}
2. ensureCapacityInternal(int minCapacity)方法:
private void ensureCapacityInternal(int minCapacity) {
//calculateCapacity:获取当前所需最小容量
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
3.calculateCapacity(Object[] elementData, int minCapacity)方法:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//这个个人存在疑问,就是True的情况应该不是发生在代码执行时
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
4.private void ensureExplicitCapacity(int minCapacity):
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //记录此List被操作了多少次,也就是能改变当前List的size操作发生了多少次
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
四.扩容算法具体操作grow(int minCapacity):
1.进行扩容操作:oldCapacity + (oldCapacity >> 1) ,
举例 :DEFAULTCAPACITY = 10 ,扩容操作为10+(10>>1)= 10 + 5 =15
>>带符号右移操作 用八位示例为: 0000 1010(10) >> 0000 0101(5)
2.进行OOM判断,当超出最大容量抛出OOMerror
3.进行扩容操作,就是建立一个新的数组,将原数组值复制,而具体的复制算法,在System包中的arrayCopy方法使用C++实现的本地方法。
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);//最大容量,并且判断OOM
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);//数组复制的具体算法 在System包的arrayCopy方法
}
疑问:(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) ,此情况未分析清楚,无论是外部调用哪种构造方法方式获取ArrayList实例后,通过Add都不触发,反射也不会触发;所以个人猜测在内存分配时使用,需要进一步学习。