ArrayList初始化
首先我们来看一段代码:
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
list1.add(1);
System.out.println(list1.size());
System.out.println(list2.size());
}
emmmmm,这是ArrayList类的最简单的使用了吧,那我们就随着程序运行先去看看构造方法是怎么实现的:
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
那我们再来看看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 = {};
/**
* 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;
emmmm从注释中我们可以看出来elementData是存储ArrayList元素的缓冲区(数组),而DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一个static类型的Object空数组,static的性质是每个类仅存在一个这种类型的变量。
那么问题来了为什么构造方法不写成这种形式呢?
public ArrayList() {
this.elementData = new Object[]{};
}
假如我们多次创建ArrayList对象并且多次调用new ArrayList();的话然后就会创建很多个空的Object空数组,而使用jdk所实现的代码不管怎样在程序运行时间内只创建了一个Object空数组,看来写这段代码的作者就是防止创建大量的Object数组导致资源浪费。
好吧我们继续执行执行到了:
list1.add(1);
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;
}
先忽略掉ensureCapacityInternal(size + 1),那就很简单了就是把新添加进来的元素直接丢进elementData数组的最后面。
那我们来看看ensureCapacityInternal()方法
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
我们还需要看看ensureExplicitCapacity()方法和calculateCapacity()方法。
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
还有grow()方法:
/**
* 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);
}
emmmm,总算是到头了,通过注释我们了解到grow()方法的作用就是为ArrayList的elemData数组扩展容量的,注意一下这条语句:
int newCapacity = oldCapacity + (oldCapacity >> 1);
话说>>这个符号我都快忘了,第一学期的时候学c语言老师提了一嘴但是没仔细讲,然后我是在那次寒假从图书馆借了一本2004《深入理解计算机系统》然后它的第一章就是讲计算机里面的数据(准确来说是内存)然后我也看不懂于是我就只是做做习题,然后习题里面都是这个玩意(位运算)。
>>是有符号右移,这个数在内存中占到的比特位最高位不变其它向右移,那么>>1就是向右移一位咯,那就是这个数除以2咯。然后你预计要的容量newCapacity就是原来容量oldCapacity的1.5倍了。
但是如果预计的容量newCapacity还是比参数最小容量minCapacity,那就只能用minCapacity作为最小容量了,然后就是把原来的数组元素复制到新的扩大的数组里面。
这我们就看完了我们就该看calculateCapacity()方法了:
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
很显然这个方法就是计算ArrayList的内部最小容量的。
到此我们就可以明确ArrayList的add()方法的作用就是把元素添加到ArrayList里面的,并且要做扩容之类的事情。