文章目录
  1. ArrayList源码分析
    1. 1. 构造函数
    2. 2. add 和 addAll 方法
    3. 3. set 和 get 方法
    4. 4. remove 方法
    5. 5. indexOf 方法 (lastIndexOf 同理)
    6. 6. 其他一些方法
    7. 7. 总结

[TOC]

ArrayList源码分析

ArrayList类的源码分析, 主要针对java1.6java1.7的进行源码的分析。如果有明显的差异, 我会明确的指出, 要是实现方式基本相同, 那比较的上面就不多说废话了, 下面开始。

类中涉及到的进行维护的变量, 这里只说主要相同的部分,

  1. private transient Object[] elementData; // 维护数据的对象数组
  2. private int size; // 维护数据元素的实际大小

下面讲述中直接用变量的名称代替.

1. 构造函数

  • new ArrayList()
1
ArrayList list = new ArrayList();

基本的构造函数调用上来就有不同
1.6中调用了该构造方法之后, elementData 的数组大小直接被初始化为 10, 源码

1.7中没有直接初始化 elementData 的大小

EMPTY_ELEMENTDATA 表示java1.7中维护的一个空数组 {}

  • new ArrayList(int initialCapacity)

这个方法就是纯粹的将 elementData 的大小直接初始化为传入的大小

  • public ArrayList(Collection<? extends E> c)

这个没啥好说的, 就是直接将传入的集合变成 Object[] 数组然后赋值给 elementData , 再将 size 数值为数组的大小.

2. add 和 addAll 方法

add 方法中涉及到一个比较重要的方法: 扩容
扩容在1.6和1.7之中唯一的区别就是每次扩容的大小。在者就是1.7中多了几个大小是否越界判断的方法。

java1.6中, 每次扩容的大小是 elementData3/2 倍再加 1

java1.7中, 每次扩容的大小是 elementData 加上 elementData1/2

它们在扩容完之后再次与minCapacity(add中是size+1,addAll中是size+传入集合的元素大小) 比较大小是因为如果调用了addAll方法传入一个集合的时候, 防止扩容之后的大小仍然小于minCapacity(size+集合的大小), 索性就直接将 minCapacity 赋值给size

3. set 和 get 方法

set和get方法中比较重要一点的方法就是对下标的大小进行校验:rangeCheck(index);

4. remove 方法

1、 remove(int index) 方法中比较重要的方法就是

1
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的效果

1
2
3
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()

  1. removeAll(Collection<?> c)retainAll(Collection<?> c) 方法

removeAll: 移除指定的元素集合
retainAll: 保留指定的元素集合

java1.7中改变这两个方法的实现, 不在采用 AbstractCollection类 中的实现
同样, java1.7中也对 listIterator()iterator() 做了自己的实现, 同时增加了新的内部类

7. 总结

java1.7中的大多数方法除了多增加几个安全判断外基本和1.6没什么两样, 改变的地方如下

  1. 默认构造函数的实现不同, java1.6直接对保存的元素数组对象 Object[] 初始化大小为10; 而java1.7默认是直接将空数组{}赋值给 Object[], 并且在扩容的方法中进行大小的初始化, 但默认也是10。
  2. java1.7和java1.6每次扩容的大小不同
  3. java1.7对一些方法做了自己的实现,如subList(), removeAll(), retainAll() 等等,并同时实现了对应的内部类。而java1.6采用的是 AbstractCollection类 和 AbstractList类 中的实现

综上:ArrayList类的实现总体上还是比较简单的, 代码精炼(不愧是java大神们写的东西), 大家在使用这些类的过程中不妨多多去研究源码, 相信肯定会有很多的收货, 不光是在记忆上还是理解上都有一些突破。大家加油。

文章目录
  1. ArrayList源码分析
    1. 1. 构造函数
    2. 2. add 和 addAll 方法
    3. 3. set 和 get 方法
    4. 4. remove 方法
    5. 5. indexOf 方法 (lastIndexOf 同理)
    6. 6. 其他一些方法
    7. 7. 总结