JAVA集合源码分析系列:ArrayList源码分析
2016-08-29 21:55
686 查看
一.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
相关文章推荐
- JAVA集合源码分析系列:TreeSet源码分析
- Java集合系列之ArrayList源码分析
- JAVA集合源码分析系列:TreeMap源码分析
- Java集合系列之HashMap源码分析
- Java集合系列之LinkedList源码分析
- Java集合系列之HashMap源码分析
- JAVA集合源码分析系列:HashMap源码分析
- Java集合源码分析系列-(一)ArrayList源码剖析
- Java集合系列之LinkedList源码分析
- Java集合系列:-----------03ArrayList源码分析
- JAVA集合源码分析系列:LinkedList源码分析
- 【Java集合学习系列】HashMap实现原理及源码分析
- JAVA集合源码分析系列:HashSet源码分析
- Java集合系列之HashSet源码分析
- Java集合系列之ArrayList源码分析
- java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
- Java 集合系列 06 Stack详细介绍(源码解析)和使用示例
- Java 集合系列 04 LinkedList详细介绍(源码解析)和使用示例
- Java 集合系列 07 List总结(LinkedList, ArrayList等使用场景和性能分析)
- java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)