首页 > 代码库 > ArrayList源码阅读
ArrayList源码阅读
ArrayList实现
继承关系
java.lang.Object
- java.util.AbstractCollection<E>
- java.util.AbstractList<E>
- java.util.ArrayList<E>
实现接口
Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess
关键属性
private transient Object[] elementData; //transient修饰不会序列化,但实现了Serializable接口,重写了readObject和writeObject方法只序列化实际大小
private int size; //实际大小
常见方法
public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
public void add(int index, E element) { if (index > size || index < 0) throw new IndexOutOfBoundsException( "Index: "+index+", Size: "+size); ensureCapacity(size+1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); //elementData[index,size) --> elementData[index+1,size+1) elementData[index] = element; size++; }ensureCapacity扩容方法:开始前有对modCount修改操作,实现fast-fail迭代
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; //0.5倍扩容策略 if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = http://www.mamicode.com/Arrays.copyOf(elementData, newCapacity);>remove方法,移动index+1及其后面元素,并将最后一个元素设置为null,帮助GC回收
public E remove(int index) { RangeCheck(index); modCount++; E oldValue = http://www.mamicode.com/(E) elementData[index];>public boolean remove(Object o) { if (o == null) { for (int index = 0; index < size; index++) if (elementData[index] == null) { fastRemove(index); return true; } } else { for (int index = 0; index < size; index++) if (o.equals(elementData[index])) { fastRemove(index); return true; } } return false; }fastRemove是私有方法没有返回old value
private void fastRemove(int index) { modCount++; int numMoved = size - index - 1; if (numMoved > 0) System.arraycopy(elementData, index+1, elementData, index, numMoved); elementData[--size] = null; // Let gc do its work }重写readObject和writeObject进行序列化和反序列化,保证只会序列化实际大小的数组避免空间浪费,可以看到writeObject的时候有fast fail判断
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in size, and any hidden stuff s.defaultReadObject(); // Read in array length and allocate array int arrayLength = s.readInt(); Object[] a = elementData = http://www.mamicode.com/new Object[arrayLength];>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 array length s.writeInt(elementData.length); // 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(); } }迭代器实现
ArrayList支持两种迭代器:Iterator和ListIterator(双向迭代),实现在AbstractList中
Iterator通过内部类AbstractList$Itr实现
Itr类定义
private class Itr implements Iterator<E>
属性包括
int cursor = 0; //当前遍历的下标
int lastRet = -1; //最近调用next或previous返回的下标,当调用自身remove方法删除元素后,重置为-1
int expectedModCount = modCount; //用于检测遍历过程中并发修改
重要方法hasnext和next方法
public boolean hasNext() { return cursor != size(); } public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } }remove方法
public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } }-next和remove方法前都需要调用checkForComodification检验容器是否被修改,若被修改则抛出ConcurrentModificationException
-调用迭代器自身remove方法不会引起ConcurrentModificationException,这是因为删除元素以后,expectedModCount被重新设置了(expectedModCount = modCount)
-可以看到remove方法执行完一次删除以后,将lastRet设置为-1,下次接着调用就会抛异常。
ListIterator通过内部类ListItr来实现,其继承了单向迭代器Itr并实现双向迭代器接口ListIterator
ListItr类定义
private class ListItr extends Itr implements ListIterator<E>
支持指定cursor位置构造
ListItr(int index) { cursor = index; }previous和next方法设置lastRet不同,next方法是cursor未加1之前的值,而previous是cursor减1以后的值
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(); } }set方法是在lastRet处修改该元素的值,向前遍历一次previous则为cursor-1,向后遍历一次则为cursor
public void set(E e) { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.set(lastRet, e); expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }add方法在当前cursor位置添加,并将cusor加1
public void add(E e) { checkForComodification(); try { AbstractList.this.add(cursor++, e); lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
总结
1. ArrayList内部通过数组方式实现,采用加倍策略而非指定常量扩容,指定位置添加采用平摊分析复杂度为O(1)
2. ArrayList中数组声明为transient不会序列化,重写了readObject和writeObject进行反序列化和序列化,保证只序列化有效大小的数组元素。
3. 迭代器支持fast-fail,当迭代过程中检测到容器结构发生变化添加或删除元素时,会抛出ConcurrentModificationException,通过内部modCount实现。调用迭代器自身remove方法和双向迭代器中add和set方法不会引起并发修改异常。
4. 迭代器中remove和set方法需要调用next或previous内部lastRet成员设置为有效索引才可以,并且调用完remove方法以后lastRet又重新设置为-1,不能直接反复调用。
参考OpenJDK 源代码阅读之 ArrayList
ArrayList源码阅读
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。