ArrayList类的源码分析, 主要针对java1.6和java1.7的进行源码的分析。如果有明显的差异, 我会明确的指出, 要是实现方式基本相同, 那比较的上面就不多说废话了, 下面开始。
类中涉及到的进行维护的变量, 这里只说主要相同的部分,
- private transient Object[]
elementData
; // 维护数据的对象数组 - private int
size
; // 维护数据元素的实际大小
下面讲述中直接用变量的名称代替.
1. 构造函数
1.1 new ArrayList()
ArrayList list = new ArrayList();
基本的构造函数调用上来就有不同
1.6中调用了该构造方法之后, elementData
的数组大小直接被初始化为 10, 源码
1.7中没有直接初始化 elementData
的大小
EMPTY_ELEMENTDATA
表示java1.7中维护的一个空数组 {}
1.2 new ArrayList(int initialCapacity)
这个方法就是纯粹的将 elementData 的大小直接初始化为传入的大小
1.3 public ArrayList(Collection<? extends E> c)
这个没啥好说的, 就是直接将传入的集合变成 Object[] 数组然后赋值给 elementData
, 再将 size
数值为数组的大小.
2. add 和 addAll 方法
add 方法中涉及到一个比较重要的方法: 扩容
扩容在1.6和1.7之中唯一的区别就是每次扩容的大小。在者就是1.7中多了几个大小是否越界判断的方法。
java1.6中, 每次扩容的大小是 elementData
的 3/2 倍再加 1
java1.7中, 每次扩容的大小是 elementData
加上 elementData
的 1/2
它们在扩容完之后再次与minCapacity(add中是size+1,addAll中是size+传入集合的元素大小)
比较大小是因为如果调用了addAll方法传入一个集合的时候, 防止扩容之后的大小仍然小于minCapacity(size+集合的大小)
, 索性就直接将 minCapacity
赋值给size
。
3. set 和 get 方法
set和get方法中比较重要一点的方法就是对下标的大小进行校验:rangeCheck(index);
4. remove 方法
remove(int index)
方法中比较重要的方法就是
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
其实这个也是整个类中用的比较多的方法, 这个方法将原对象src中srcPos下标开始, 复制到目标对象dest的下标destPos开始, 复制length个的元素。最后在维护一下 size 的大小
remove(Object o)
方法其实就是获取元素的下标, 然后再次调用上述的删除方法。
这里的 fastRemove(index)
方法与上述的remove(int index) 方法基本一模一样, 代码重复了
2、protected void removeRange(int fromIndex, int toIndex)
方法
这个方法是一个受保护的方法, 要想实现这种效果就需要调用subList方法返回一个子集合, 然后在调用clear()方法, 最后的导致的结果就是原来的list调用了removeRange的效果
list.subList(start, end).clear();
// 参考 http://stackoverflow.com/questions/2289183/why-is-javas-abstractlists-removerange-method-protected
list.subList(start, end)
实际返回了一个SubList类
这里的clear()
方法其实就是调用了 removeRange(0,size())
的方法, 接着看下subList类中的removeRange方法
这里,l
代表的就是原来集合, 接着隐含调用了原来集合的 removeRange 方法。
但是在java1.7中对subList方法做了自己的实现,并且在自己增了加SubList内部类, 但是基本实现原理基本一致。
5. indexOf 方法 (lastIndexOf 同理)
6. 其他一些方法
1.trimToSize()
, 将 elementData
的大小变成实际元素的个数大小, 节省了内存空间
2. size()
3. isEmpty()
4. contains(Object 0)
5. clear()
6. removeAll(Collection<?> c)
和 retainAll(Collection<?> c)
方法
removeAll: 移除指定的元素集合
retainAll: 保留指定的元素集合
java1.7中改变这两个方法的实现, 不在采用 AbstractCollection类
中的实现
同样, java1.7中也对 listIterator()
和 iterator()
做了自己的实现, 同时增加了新的内部类。
7. 总结
java1.7中的大多数方法除了多增加几个安全判断外基本和1.6没什么两样, 改变的地方如下
- 默认构造函数的实现不同, java1.6直接对保存的元素数组对象 Object[] 初始化大小为10; 而java1.7默认是直接将空数组{}赋值给 Object[], 并且在扩容的方法中进行大小的初始化, 但默认也是10。
- java1.7和java1.6每次扩容的大小不同
- java1.7对一些方法做了自己的实现,如subList(), removeAll(), retainAll() 等等,并同时实现了对应的内部类。而java1.6采用的是 AbstractCollection类 和 AbstractList类 中的实现
综上:ArrayList类的实现总体上还是比较简单的, 代码精炼(不愧是java大神们写的东西), 大家在使用这些类的过程中不妨多多去研究源码, 相信肯定会有很多的收货, 不光是在记忆上还是理解上都有一些突破。大家加油。