ArrayList 源码解析(JDK1.7)
ps: 我思考了一下…想要不要发这篇博客… 感觉作为一个初学者…发这种源码解析… 尤其当做学习记录这样的东西来做…感觉没有任何的重点可言… 不过思考了一下…反正估计也没人看 (狗头) 就发了吧
纯属个人 … emmm 萌新的学习经历- -
大伙凑着看看吧…如果有错 , 请指出…
快速导航
ArrayList的层次结构
接口
Iterable (可迭代的)
public interface Iterable<T> {
//没啥好说的..获得一个迭代器
Iterator<T> iterator();
}
Collection (集合)
public interface Collection<E> extends Iterable<E> {
int size(); //获得集合大小
boolean isEmpty(); //判断是否为空
boolean contains(Object o); //判断集合内是否包含元素
Iterator<E> iterator(); //获得集合的迭代器
Object[] toArray(); //将集合转为Object数组
<T> T[] toArray(T[] a); //将结合转为T数组
boolean add(E e); //添加一个元素
boolean containsAll(Collection<?> c); //是否包括了另外一个集合
boolean addAll(Collection<? extends E> c); //添加另外一个集合的所有元素
boolean retainAll(Collection<?> c); //保留c集合中的所有元素
void clear(); //将集合清空
// Object的方法 重写
boolean equals(Object o);
int hashCode();
}
List (列表)
public interface List<E> extends Collection<E> {
//省略了从Collection 扩展的一些接口
//....
boolean addAll(int index, Collection<? extends E> c); //从index的位置处 插入一个集合
E get(int index); //通过index获得值
E set(int index, E element); //设置值(修改)
void add(int index, E element); //在某个位置插入一个值
E remove(int index); //移除index位置的值
int indexOf(Object o); //查找o元素在列表中的位置
int lastIndexOf(Object o); //查找最后一个o出现的位置
ListIterator<E> listIterator(); //获得列表的迭代器
ListIterator<E> listIterator(int index); //获得从index开始的列表
List<E> subList(int fromIndex, int toIndex); //截取一个小的列表
}
Cloneable (可拷贝的)
public interface Cloneable { //是个用于标记的接口
//只有实现了这个接口的类..才可以使用Object.Clone() 方法(动态方法) 对象.clone()
}
Serializable (可序列化的)
public interface Serializable {
//也是用于标记的接口..签名
//实现了这个接口的类, 可序列化
}
RandomAccess (随机访问)
public interface RandomAccess {
//也是一个标记接口...用于加速随机访问..
//用于底层的优化..
}
抽象类
AbstractCollection(抽象的集合)
public abstract class AbstractCollection<E> implements Collection<E> {
//抽象类 ...没啥好说的感觉... 主要是实现了 Collection的绝大部分方法..除了 iterator 和 size 方法没实现
//这里就分析一下它的private方法相关的东西 (以及 调用了这些方法的方法)
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //注意..列表的容量最大值是不允许超过 Integer.MAX_VALUE - 8 ...原因是 说 有些VM 中会在列表里面加入一些header work..可能会占用一些..
public Object[] toArray() {
// Estimate size of array; be prepared to see more or fewer elements
Object[] r = new Object[size()];
// 设计这个的时候...设计者的想法可能 size() 得到的是估计值..不是绝对的精确..
Iterator<E> it = iterator();
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) // fewer elements than expected
return Arrays.copyOf(r, i);
r[i] = it.next();
}
//走到这里的条件是 r的大小 >= 列表的大小
//如果r的大小等于列表的大小..就会返回r
//否则就是返回 finishToArray方法.
return it.hasNext() ? finishToArray(r, it) : r;
}
public <T> T[] toArray(T[] a) {
// Estimate size of array; be prepared to see more or fewer elements
int size = size();
T[] r = a.length >= size ? a :
(T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
//这边也是类似上面的方法.. 首先判断 a元素大小够不够..如果不够 先扩容
Iterator<E> it = iterator();
/**
如果 a 是 [1,2,3,4,5,6]
列表是 [2,3]
最后的返回值 就是 a 为[2,3,null,4,5,6]...感觉好怪异
总的来说..调用这个方法之后, 信任返回值比较好..传入值有时改有时不会改
**/
for (int i = 0; i < r.length; i++) {
if (! it.hasNext()) { // 如果列表的值 是 数组小...
if (a == r) { //a原本就比估计的要大
r[i] = null; //最后一个元素设置为null...
} else if (a.length < i) { //r是调用反射生成的.. a的大小 < 列表的大小元素大小
return Arrays.copyOf(r, i); //压缩掉r的大小
} else { //我觉得这种情况就很怪异
//r 是通过反射生成的..r的大小应该就是列表大小...能到这里, 就说明了 列表的大小 < r的大小
//这个分支是 a的大小 >= 列表元素大小
//总结起来就是 : 调用的时候 a的大小 < 列表元素大小
//中间发生了未知的情况造成 列表元素疯狂下降..下降到 a的大小 > 列表元素大小
System.arraycopy(r, 0, a, 0, i);
if (a.length > i) {
a[i] = null;
}
}
return a;
}
r[i] = (T)it.next();
}
//与上一个方法同理...
return it.hasNext() ? finishToArray(r, it) : r;
}
/*
进入这个方法的原因是 列表的实际元素数量 比 r要大
首先保留i 也就是index 下标..从r的第i个元素开始填充
然后将r进行扩容...遵照list的扩容方式.. 1.5倍的扩容
**/
private static <T> T[] finishToArray(T[] r, Iterator<?> it) {
int i = r.length;
while (it.hasNext()) {
int cap = r.length;
if (i == cap) {
int newCap = cap + (cap >> 1) + 1;
// overflow-conscious code
if (newCap - MAX_ARRAY_SIZE > 0)
newCap = hugeCapacity(cap + 1);
r = Arrays.copyOf(r, newCap);
}
r[i++] = (T)it.next();
}
// trim if overallocated
return (i == r.length) ? r : Arrays.copyOf(r, i);
}
//防止扩容过大..
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError
("Required array size too large");
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
}
AbstractList (抽象的列表)
//开始慢慢复杂
//在抽象集合中没有实现的2个方法 . 在这里类中 实现了 具体的获得迭代器的方法
// list 接口中的 get(int index) 方法没有实现
// 当然 在这个类中. 其他的一些增删改(list接口中)的操作 都是 抛出UnsupportedOperationException的 , 只能get..虽然没有实现
//但是 它新加了自己的一些remove方法...
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
//已经被实现的方法..这里都不介绍了 . 具体抽出一些新加入的东西
protected transient int modCount = 0; // 这个属性 记录着 集合的修改次数..主要用于 迭代器在遍历的时候 检测集合是否发生过修改...
/**
这个方法的意思么 就是移除这个区间里的元素.. 主要的关注点在于它的 迭代器的实现
**/
protected void removeRange(int fromIndex, int toIndex) {
ListIterator<E> it = listIterator(fromIndex);
for (int i=0, n=toIndex-fromIndex; i<n; i++) {
it.next();
it.remove();
}
}
//这俩方法都是获取该集合的迭代器
public ListIterator<E> listIterator() {
return listIterator(0);
}
public ListIterator<E> listIterator(final int index) {
rangeCheckForAdd(index);
return new ListItr(index);
}
//实现了可迭代器的接口..具有迭代的能力
private class Itr implements Iterator<E> {
int cursor = 0; //游标..标记着 下一个遍历的元素下标
//在代码中也能看出..记录着 cursor的上一值
int lastRet = -1; //最后一次调用 next 或者 previous 返回的下标 如果发生了remove 这个值又会变成-1
int expectedModCount = modCount; //用来检测集合是否发生了值的变化.. 保证了在集合迭代的过程中不会发生改变
public boolean hasNext() { //是否有下一个..元素
return cursor != size();
}
public E next() { //获得下一个元素前
checkForComodification(); //要检测一下集合是否发现了改变
try {
int i = cursor;
E next = get(i);
lastRet = i;
cursor = i + 1;
return next;
} catch (IndexOutOfBoundsException e) { //后检测..通过抛出异常来检测是否越界
checkForComodification();
throw new NoSuchElementException();
}
}
//移除元素 ...虽然最后还是调用的 AbstractList的remove 方法
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1; // 这里也就意味着 不能连续2次 remove
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() { //集合是否发生了修改
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
/**
列表的迭代器实现.. 看这里继承了一个 叫做Itr的类
这个类 也是其中一个内部类..就在上方
在能够迭代的基础上 还实现了 列表的迭代器..这个迭代器..又能向后 又能向前
还能够支持 set 和 add方法
**/
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E e) {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, e);
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
public void add(E e) {
checkForComodification();
try {
int i = cursor;
AbstractList.this.add(i, e);
lastRet = -1;
cursor = i + 1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
}
//这个方法也是来自 list接口的 获得一段 子列表.. 里面涉及了2个类 (下面2个)
public List<E> subList(int fromIndex, int toIndex) {
return (this instanceof RandomAccess ?
new RandomAccessSubList<>(this, fromIndex, toIndex) :
new SubList<>(this, fromIndex, toIndex));
}
}
//普通的子列表
/**
大局浏览一下代码...
发现并没有真实的再去取一段列表
而是使用了源列表之后, 限定了一段区间...
获取方式 使用 index + 偏移量的形式获取
*/
class SubList<E> extends AbstractList<E> {
private final AbstractList<E> l;
private final int offset;
private int size;
SubList(AbstractList<E> list, int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > list.size())
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
l = list;
offset = fromIndex;
size = toIndex - fromIndex;
this.modCount = l.modCount;
}
public E set(int index, E element) {
rangeCheck(index);
checkForComodification();
return l.set(index+offset, element);
}
public E get(int index) {
rangeCheck(index);
checkForComodification();
return l.get(index+offset);
}
public int size() {
checkForComodification();
return size;
}
public void add(int index, E element) {
rangeCheckForAdd(index);
checkForComodification();
l.add(index+offset, element);
this.modCount = l.modCount;
size++;
}
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = l.remove(index+offset);
this.modCount = l.modCount;
size--;
return result;
}
protected void removeRange(int fromIndex, int toIndex) {
checkForComodification();
l.removeRange(fromIndex+offset, toIndex+offset);
this.modCount = l.modCount;
size -= (toIndex-fromIndex);
}
public boolean addAll(Collection<? extends E> c) {
return addAll(size, c);
}
public boolean addAll(int index, Collection<? extends E> c) {
rangeCheckForAdd(index);
int cSize = c.size();
if (cSize==0)
return false;
checkForComodification();
l.addAll(offset+index, c);
this.modCount = l.modCount;
size += cSize;
return true;
}
public Iterator<E> iterator() {
return listIterator();
}
public ListIterator<E> listIterator(final int index) {
checkForComodification();
rangeCheckForAdd(index);
return new ListIterator<E>() {
private final ListIterator<E> i = l.listIterator(index+offset);
public boolean hasNext() {
return nextIndex() < size;
}
public E next() {
if (hasNext())
return i.next();
else
throw new NoSuchElementException();
}
public boolean hasPrevious() {
return previousIndex() >= 0;
}
public E previous() {
if (hasPrevious())
return i.previous();
else
throw new NoSuchElementException();
}
public int nextIndex() {
return i.nextIndex() - offset;
}
public int previousIndex() {
return i.previousIndex() - offset;
}
public void remove() {
i.remove();
SubList.this.modCount = l.modCount;
size--;
}
public void set(E e) {
i.set(e);
}
public void add(E e) {
i.add(e);
SubList.this.modCount = l.modCount;
size++;
}
};
}
public List<E> subList(int fromIndex, int toIndex) {
return new SubList<>(this, fromIndex, toIndex);
}
private void rangeCheck(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkForComodification() {
if (this.modCount != l.modCount)
throw new ConcurrentModificationException();
}
}
//实现方式与 子列表相同....就是再次获取 子列表稍微不一样
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
RandomAccessSubList(AbstractList<E> list, int fromIndex, int toIndex) {
super(list, fromIndex, toIndex);
}
public List<E> subList(int fromIndex, int toIndex) {
return new RandomAccessSubList<>(this, fromIndex, toIndex);
}
}
正餐 ArrayList (正主)
这里就不把整个类代码抓起来逐行看了…(代码比较长)…
对于一个类…我喜欢先从成员变量…属性…来看… 假设一些成员变量的作用…方法里使用到之后就能确定是否正确
成员变量
让我们先来看 它的成员变量
private static final int DEFAULT_CAPACITY = 10; //默认的容量大小
private static final Object[] EMPTY_ELEMENTDATA = {}; //可能
private transient Object[] elementData; //底层使用的是 Object[] 数组来存储元素
private int size; //元素的大小
//这里 -8的原因 在上文中提到了...根据源码的解释..是说VM里面要在列表这个类型中 加入 header word..
//ps : 具体啥情况- -我也不知道..
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //数组最大的长度.
实例方法
public ArrayList(int initialCapacity) { //如果指定一个值进行初始化...就会直接进行初始化
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
}
public ArrayList() {
super();
//注意这里! 如果使用默认的话...不会先初始化!!!!! 会先使用一个空的数组进行标记..然后在第一次add的时候,扩容
this.elementData = EMPTY_ELEMENTDATA;
}
public ArrayList(Collection<? extends E> c) { //可以带一个集合进来
elementData = c.toArray();
size = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
}
如果把每个方法都拿出来分析…就有些冗余了…
重要方法
// add
public boolean add(E e) {
ensureCapacityInternal(size + 1); //主要是这个方法... 涉及了扩容机制
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == EMPTY_ELEMENTDATA) { //如果使用默认方法构造..第一次会进入这里
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
//明确是否要扩容 参数传入是 add之后的容量大小
private void ensureExplicitCapacity(int minCapacity) {
modCount++; //可能会涉及数组的结构变化...因此要改变当前的修改值..如果有迭代器正在遍历..
//迭代器将会抛出错误
// overflow-conscious code
if (minCapacity - elementData.length > 0) // 如果当前容量不满足了..就需要发生扩容
grow(minCapacity);
}
//扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //这里也是重要的地方.以原来1.5倍的大小进行扩容
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);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
// 可以让用户主动 更改 列表的容量的2个方法 trimTosize
和 ensureCapacity(int)
//没啥好说的..主动扩容到 minCapacity 加上一点点小判断.
public void ensureCapacity(int minCapacity) {
int minExpand = (elementData != EMPTY_ELEMENTDATA)
? 0
: DEFAULT_CAPACITY;
if (minCapacity > minExpand) {
ensureExplicitCapacity(minCapacity);
}
}
//主动减少容量
public void trimToSize() {
modCount++;
if (size < elementData.length) {
elementData = Arrays.copyOf(elementData, size);
}
}
// 用于 对象流的 writeObject
和 readObject
这俩东西 我当时看的也是很蒙的… 发现没有方法调用这俩方法… 又是private的…
一番百度才知道…这是 使用在 对象流里面的… 对象流 会自动通过反射 调用这两个类…
出现这俩个类的原因是 : 存储数据的
private transient Object[] elementData;
是 transient关键字不会被序列化… 当然不会被序列化也是考虑过的…因为 这个东西的大小通常比实际数据要大的多…
为了空间不被浪费
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
elementData = EMPTY_ELEMENTDATA;
s.defaultReadObject();
s.readInt();
if (size > 0) {
// be like clone(), allocate array based upon size not capacity
ensureCapacityInternal(size);
Object[] a = elementData;
// Read in all elements in the proper order.
for (int i=0; i<size; i++) {
a[i] = s.readObject();
}
}
}
//
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException{
// Write out element count, and any hidden stuff
int expectedModCount = modCount;
s.defaultWriteObject();
// Write out size as capacity for behavioural compatibility with clone()
s.writeInt(size);
// Write out all elements in the proper order.
for (int i=0; i<size; i++) {
s.writeObject(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
内部的迭代器
和AbstractList中的迭代器实现方式 几乎相同 . 这里就不说了
SubList
因为ArrayList 是实现RandomAccess的 , 因此 和 AbstractList 比起来 默认就是 RandomAccess型
结束! …
又是摸鱼的一天 唉 苦逼