最近把数据结构的链表复习了一遍,感觉就是在刨jdk里的源码.链表的实现和ArrayList 底层都是用数组来实现,
基本的方法实现都非常相似,ArrayList 随着jdk的升级多了一些信新的特性。重点还是来看看里面的扩容是怎么来实现的?
ArrayList 共实现三个接口,RandomAccess,Cloneable,Serializable,继承 AbstractList类。
/**
序列化
*/
private static final long serialVersionUID = 8683452581122892189L;
/**
* 默认初始化容量大小
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 定义一个空数组
*/
private static final Object[] EMPTY_ELEMENTDATA = {};
/**
* 默认的空数组
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
/**
* 实际存储的数组
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
数组实际大小
*/
private int size;
ArraList的构造函数
- ArrayList(int initialCapacity) 如果初始值大于0则新建一个大小为initialCapacity 的数组赋值给当前实际存储的数组
如果 initialCapacity 初始值等于0 则当前实际存储的数组设为空数组,
如果初始值小于则这直接抛出异常
无惨构造函数,直接默认的空数组赋值给当前的实际数组
就是参数为 Collection 的构造函数,可以存放实现 Collection 接口下的 list ,set 等
到这里似乎还没看到跟ArrayList的扩容相关的,看看他的add方法是如何来实现的
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return <tt>true</tt> (as specified by {@link Collection#add})
*/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
将元素e赋值之前 ensureCapacityInternal(size+1) 操作,重点来关注该系列方法
**关于安全扩容共有3个方法 **
- ensureCapacity(int minCapacity) 获取最小延伸值 minExpand ,比较最小延伸值与最小初始值大小从而来执行
ensureExplicitCapacity(minCapacity) 方法
- ensureCapacityInternal(int minCapacity) 方法,先判断 当前数组与默认的空数组是否相等,若成立 则最小初始化值为
默认值与原最小初始化值二者之间的最大值。 最后调用 ensureExplicitCapacity(minCapacity) 该方法
- ensureExplicitCapacity(int minCapacity), modeCount 是在 AbstractList 抽象类里面定义的
protected transient int modCount = 0; transient 关键字 序列化对象的时候,这个属性就不会序列化到指定的目的地中
判断是否扩容的关键就在 if语句里面 ,if(minCapacity - elementData.length > 0) 就是最小初始化值大于当前实际存储数组的值,则调用grow(minCapacity) 方法
判断是否扩容的关键就是 最小初始值大于当前实际存储数组的长度
ArrayList的扩容 grow(minCapacity)
/**
* grow() 方法是ArrayList扩容的关键
右移一位相当于除2,右移n位相当于除以2的n次方。
如果 oldCapacity =11 ,则 (oldCapacity >> 1) 结果就是5
关于位移运算,可以下去研究一下
*/
private void grow(int minCapacity) {
// overflow-conscious code
// 原容量等于当前数组的长度
int oldCapacity = elementData.length;
// 新的容量等于原始容量+原始容量右移一位
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 如果新的初始容量减去最小容量小于0 则新容量等最小初始容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 如果新容量减去最大数组值大于0则新的容量则新容量等于Integer.MAX_VALUE 或者MAX_ARRAY_SIZE
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
// 然后copy一份之前的数组和最新的容量赋值给之前数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
ArrayList的新容量是原容量右移一位加上原容量值,看完源码后试图自己写一个ArrayList集合。