我们现在来看ArrayList的成员变量,在上一篇博客中我们探究了Arraylist的最大容量,下面我们来看看其他的成员变量。
- size
/**
* The size of the ArrayList (the number of elements it contains).
* ArrayList的大小(它包含的元素数)。
* @serial
*/
private int size;
此成员变量是用来描述ArrayList的大小的
java的成员变量是有默认值的,这也是为什么ArrayList中没有对size初始化的代码,但是却可以直接使用的原因。以下内容可以作为了解
//下面是在类中定义的成员变量
private boolean bool;//默认值是false
private byte bt;//默认值是0
private short st;//默认值是0
private char ch;//默认值是空字符('\u0000')
private int i;//默认是0
private long l;//默认是0
private float f;//默认是0.0
private double d;//默认是0.0
private String str;//默认是null
2.static final int DEFAULT_CAPACITY
/**
* Default initial capacity.
* 默认初始容量
*/
private static final int DEFAULT_CAPACITY = 10;
此静态成员变量的定义用来作为默认初始容量,用于在ArrayList中使用,但并不是指Arraylist在new出来时容量就是10,这个后续会有解释。
- static final Object[] EMPTY_ELEMENTDATA = {}即static final Object[] EMPTY_ELEMENTDATA = new Object[0]。还有static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}即static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = new Object[0];
/**
* 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 = {};
这里我们发现EMPTY_ELEMENTDATA和DEFAULTCAPACITY_EMPTY_ELEMENTDATA的值是相同的,那么为什么要定义这两个成员变量呢?看到DEFAULTCAPACITY_EMPTY_ELEMENTDATA的注释解释是我们将其与空元素数据区分开,以知道何时充气添加第一个元素。这是什么意思呢,我们来看一下下面几个方法,包含2个构造函数和一个计算容量的方法
/**
* 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;
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
可以发现当你使用带参的构造函数指定初始数组的长度时,如果长度为0,那么会使用EMPTY_ELEMENTDATA,当你是否不带参的构造函数时,使用DEFAULTCAPACITY_EMPTY_ELEMENTDATA。
而在对数据进行操作是,比如add一个元素时会调用calculateCapacity方法计算容量,如果elementData 为DEFAULTCAPACITY_EMPTY_ELEMENTDATA就返回容量为DEFAULT_CAPACITY 也就是上面提的到一个成员变量,置位10。
但是如果elementData 不为DEFAULTCAPACITY_EMPTY_ELEMENTDATA时,返回的容量便是minCapacity。
我们以下面为例
ArrayList list1 = new ArrayList(0);
ArrayList list2 = new ArrayList();
//则list1.elementData为EMPTY_ELEMENTDATA
//而list2.elementData为DEFAULTCAPACITY_EMPTY_ELEMENTDATA
那么我们在调用add方法时,可以知道list1的容量扩展为1,而list2扩容为10.
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
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);
}
我们可以看到,上面方法中使用了成员变量elementData进行了对比。elementData也是我们要看的最后一个成员变量
- 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.
* 存储ArrayList元素的数组缓冲区。ArrayList的容量是这个数组缓冲区的长度。
* 任何elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA的空ArrayList
* 当添加第一个元素时,将扩展到DEFAULT_CAPACITY的容量。
*/
transient Object[] elementData; // non-private to simplify nested class access
这也是ArrayList的主要操作对象,我们往集合中添加和操作元素时实际上就是对数据elementData的操作。
可以发现elementData被transient 修饰,这个修饰符是防止序列化时java自带的序列化对没有填满的数组中,未填充部分进行序列化的操作而添加的。不过ArrayList中自定义了 writeObject 和 readObject 方法时,JVM 会调用这两个自定义方法来实现序列化与反序列化。这个只实现会在后续整理。
至此,ArrayList中的成员变量整理结束,有意思的点就是ArrayList的最大容量,EMPTY_ELEMENTDATA 与DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为什么内容相同还要定义2个成员变量,以及不同构造函数下,添加第一个元素时,Arraylist扩容的容量探究。