在首先进入ArrayList源码的时候,看到的先是它的继承关系,ArrayList一定是其他类的子类,而它的父类就是AbstractList<E>。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
对于后续两个类Cloneable和java.io.Serializable很好理解,应该是为了实现ArrayList的克隆,和一些自定义的对象的序列化,也就是非int,double,char这种基础类型。
/**
* 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 = {};
对于ArrayList而言。它默认的数组长度大小是10,并且有两个不一样的空数组。第一个Empty_ElementData,从取名就可以知道,这是一个空的对象数据;而第二个DefaultCapacity_Empty_ElementData,是默认空的对象数据。明明两个的值都是一样的,为什么要特别的区分开来呢?虽然注释里面解释了,当我还是想知道啥时候这两个会开始使用,于是我找到了构造方法。
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
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);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
ArrayList的两个构造方法,一个传递参数,一个不需要传递参数。当传递的参数为0,也就是ArrayList(0)的时候,elementData将设置成为Empty_ElementData。而当不传递参数的时候,elementData将设置成为DefaultCapacity_Empty_ElementData。可是我还是搞不懂为什么要区分开来?后续找到了调用的地方。
/**
* Increases the capacity of this <tt>ArrayList</tt> instance, if
* necessary, to ensure that it can hold at least the number of elements
* specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
// any size if not default element table
? 0
// larger than default for default empty table. It's already
// supposed to be at default size.
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
这段代码在注释中解释的很清楚,确保容量。在扩容之前,ArrayList会进行判断,如果说这个ArrayList在创建的时候,elementData是名字最长的那个DefaultCapacity_Empty_ElementData,那么认为这个数组最小的容量就是默认容量为10,否则就是0.这里使用的是一个三目运算符来判断。
这里我就差不多理解了,如果在使用ArrayList时,我们传递了一个为0的int参数,那么,ArrayList就会认为,要建立一个长度为0的对象数组。如果我们不传递参数,ArrayList就创建一个空对象数组,但是,当你后续对这个数组进行操作,比如,想让它成为数组长度为2的ArrayList。这时候,人家就不会这么麻烦再去确保最小的容量了,因为你当时不传递参数进去,多长也不知道,ArrayList自动帮你视为长度为10的数组对象。嗯,我觉得是这样的。后续会进入ensureExplicitCapacity的方法中,接着看下去。
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
果然,和我预想的差不多。但是,等等,有一个陌生的变量混了进来?modCount是什么时候定义的?于是我找遍了整个ArrayList也没有找到定义这个modCount的代码行数,于是我觉得它应该是在父类里面。于是进入了父类的源码寻找,果然立马就找到了。这里贴上代码:
/**
* The number of times this list has been <i>structurally modified</i>.
* Structural modifications are those that change the size of the
* list, or otherwise perturb it in such a fashion that iterations in
* progress may yield incorrect results.
*
* <p>This field is used by the iterator and list iterator implementation
* returned by the {@code iterator} and {@code listIterator} methods.
* If the value of this field changes unexpectedly, the iterator (or list
* iterator) will throw a {@code ConcurrentModificationException} in
* response to the {@code next}, {@code remove}, {@code previous},
* {@code set} or {@code add} operations. This provides
* <i>fail-fast</i> behavior, rather than non-deterministic behavior in
* the face of concurrent modification during iteration.
*
* <p><b>Use of this field by subclasses is optional.</b> If a subclass
* wishes to provide fail-fast iterators (and list iterators), then it
* merely has to increment this field in its {@code add(int, E)} and
* {@code remove(int)} methods (and any other methods that it overrides
* that result in structural modifications to the list). A single call to
* {@code add(int, E)} or {@code remove(int)} must add no more than
* one to this field, or the iterators (and list iterators) will throw
* bogus {@code ConcurrentModificationExceptions}. If an implementation
* does not wish to provide fail-fast iterators, this field may be
* ignored.
*/
protected transient int modCount = 0;
仅仅对这一个变量的注释,就比一个方法的注释还要多,看来这个modCount肯定很重要。在撇脚的英语下,我勉强读懂了注释,这个数的作用,就是为了记录整个list改动的次数或者说是整个这些东西被改动的次数,而这个数在iterators中很重要。如果稍有不慎,在使用next,set,add,remove,previous这些方法时就会抛出异常。现在还不是很需要了解这个,只需要理解成为记录数组变动次数的int值。咱们继续看下去:
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
这个grow方法,在整个ArrayList源码中只在ensureExplicitCapacity使用,也就是说,ArrayList需要扩大容量上限的时候才会调用ensureCapacityInternal去扩大。比如说,一个ArrayList有自己的默认容量大小,当你实际的容量超过了ArrayList给你预留的容量大小后,它才会去增大它的预留容量。这也就是newCapacity为什么是在oldCapacity的基础上只增大了(oldCapacity>>1)的原因,为了尽量少的去占用内存(应该是这样。)
总结:
当我们新建一个ArrayList的时候,如果没有指定大小,且没有使用ensureCapacity去预设它的大小(容量),那么它会为你预留一个长度为10的数组。当你下次添加对象进去时,就不用再次去专门扩大最小存储容量。