您的位置:首页 > 编程语言 > Java开发

JDK源码浅析之ArrayList类

2016-05-01 14:36 447 查看
以下解析基于JDK8.0

ArrayList的继承关系如下:

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
ArrayList的底层是用数组实现的:

transient Object[] elementData; // non-private to simplify nested class access
ArrayList的默认初始化大小是10:

/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;


比如说ArrayList mylist = new ArrayList(); mylist.add(new Object());在这种情况下,第一次add一个元素,则mylist的容量扩展为10(上面这个默认初始化大小为10貌似容易引起误会,以为是ArrayList对象刚new出来容量就初始化为10了,其实并没有。不过在初始化ArrayList的时候确实可以调用一个带参数的构造函数以指定初始化的容量:如ArrayList mylist = new ArrayList(20);这样的话对象一new出来容量就为20了,两个构造函数如下:)

public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
上面出现的两个常量如下所示:

/**
* 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 = {};
两个常量都是static final类型的空数组,之所以要有第二个常量DEFAULTCAPACITY_EMPTY_ELEMENTDATA是为了能够在第一次add元素需要进行扩容的时候判断是否将容量扩充为默认初始化容量10(如果这个容量足够的话)。上面代码中的注释说的就是这个意思。我们可以看一下add方法的代码:

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) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}

ensureExplicitCapacity(minCapacity);
}


ArrayList的扩容机制是每次增长为原容量的1.5倍,具体代码如下:

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);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
从代码中可以看出,如果一次扩容还达不到minCapacity的时候则新容量直接赋值为minCapacity(所以扩容的增长路线并不一定是10,15,22……这样增长的,而且初始化的时候也还可以指定容量),同时从上述代码最后一行也可以看出来,所谓的扩容就是把数组元素复制到一个更大空间的数组中。

再来看一下remove方法:

public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
注意到在查找要删除的元素时采用的是equals方法,因此添加到ArrayList中的元素所属的类(尤其是我们自定义的类)最好需要重写一下equals方法,否则得到的结果可能并不是你想要的。从上面代码我们还能看出来的一点是ArrayList里面可以包含null元素,为了避免出现空指针异常,上面的代码分别处理了元素为null以及不为null的情况。

ArrayList中还包含很多其他的方法,在这里就不一一列举了。水平有限,如有不当之处,还望指正!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ArrayList java