一.ArrayList简介
ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量能动态增长。它继承于AbstractList,实现了List, RandomAccess, Cloneable, java.io.Serializable这些接口。
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
ArrayList 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在ArrayList中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。稍后,我们会比较List的“快速随机访问”和“通过Iterator迭代器访问”的效率。
ArrayList 实现了Cloneable接口,即覆盖了函数clone(),能被克隆。
ArrayList 实现java.io.Serializable接口,这意味着ArrayList支持序列化,能通过序列化去传输。
二.ArrayList源码解析
ArrayList包含了两个重要的对象:elementData 和 size。
(01) elementData 是”Object[]类型的数组”,它保存了添加到ArrayList中的元素。实际上,elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。elementData数组的大小会根据ArrayList容量的增长而动态的增长,具体的增长方式,请参考源码分析中的ensureCapacity()函数。
(02) size 则是动态数组的实际大小。
1.构造函数
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);
}
}
这里可以看到,在初始化ArrayList的时候,我们可以给它传递一个参数initialCapacity,如果initialCapacity>0,这个参数就是elementData数组的初始大小。如果=0,系统会给elementData数组一个默认的大小
2.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);
}
这个方法的大致意思是:当我们第一次new一个ArrayList的时候,size为0,我们执行add方法,minCapacity取的值为DEFAULT_CAPACITY(10),就是说如果我们在第一次new ArrayList的时候,如果我们不设定动态数组的初始大小,则库会给一个默认的大小10.
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
如果minCapacity大于elementData数组的长度,就需要对数组进行扩容,具体的扩容的方法是:grow方法,我们看一下grow方法的实现:
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);
}
扩容时,有一个最大的限制:MAX_ARRAY_SIZE=Integer.MAX_VALUE – 8;根据以上的代码可以看出新的容量=3倍的旧容量。
至于具体的扩容方案:Arrays.copyOf(elementData, newCapacity);这个API的作用是:
copyOf()是系统自动在内部新建一个数组,调用arraycopy()将original内容复制到copy中去,并且长度为newLength。返回copy; 即将原数组拷贝到一个长度为newLength的新数组中,并返回该数组。
三.总结
通过源码的阅读,我们发现ArrayList的内部实现是数组,我们在大学学习《数据结构》的时候就知道,相比链表,数组的特点是查找方便,但是增加元素、移除元素比较慢(除非在最后的位置上操作)。我们可以根据具体的应用场景来选择合适的数据结构。
以下博客对数组和链表做了对比:
http://blog.csdn.net/u014082714/article/details/44259029
说明:
以上我阅读的是jdk1.8.0_65,不同版本可能实现有所差异不一样
http://www.cnblogs.com/skywang12345/p/3308556.html
http://www.jianshu.com/p/085a5ba2aca8