java源码分析之集合框架 ArrayList 03

java源码分析之集合框架 ArrayList 03

《java源码分析之集合框架 ArrayList 03》

ArrayList就是传说中的动态数组,就是Array的复杂版本,它提供了如下一些好处:动态的增加和减少元素、灵活的设置数组的大小……

首先看到对ArrayList的定义:

public class ArrayList<E> extends AbstractList<E>  implements List<E>, RandomAccess, Cloneable, java.io.Serializable  

从ArrayList<E>可以看出它是支持泛型的,它继承自AbstractList,实现了List、RandomAccess、Cloneable、java.io.Serializable接口。

AbstractList提供了List接口的默认实现(个别方法为抽象方法)。 
List接口定义了列表必须实现的方法。

RandomAccess是一个标记接口,接口内没有定义任何内容。

实现了Cloneable接口的类,可以调用Object.clone方法返回该对象的浅拷贝。

通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。序列化接口没有方法或字段,仅用于标识可序列化的语义。

ArrayList的属性 

ArrayList定义只定义类4个私有属性:

  /**
     * Default initial capacity.
     */
    private static final int DEFAULT_CAPACITY = 10; //数组初始时大小


    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};


    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     */
    private transient Object[] elementData;//<span style="color: rgb(54, 46, 43); font-family: "microsoft yahei"; font-size: 14px; line-height: 26px;">elementData存储ArrayList内的元素</span>


    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size; //<span style="color: rgb(54, 46, 43); font-family: "microsoft yahei"; font-size: 14px; line-height: 26px;">size表示它包含的元素的数量</span>

有个关键字需要解释:transient

Java的serialization提供了一种持久化对象实例的机制。当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。 
transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。

有点抽象,看个例子应该能明白:

public class UserInfo implements Serializable {  
     private static final long serialVersionUID = 996890129747019948L;  
     private String name;  
     private transient String psw;  

     public UserInfo(String name, String psw) {  
         this.name = name;  
         this.psw = psw;  
     }  

     public String toString() {  
         return "name=" + name + ", psw=" + psw;  
     }  
 }  

 public class TestTransient {  
     public static void main(String[] args) {  
         UserInfo userInfo = new UserInfo("张三", "123456");  
         System.out.println(userInfo);  
         try {  
             // 序列化,被设置为transient的属性没有被序列化  
             ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(  
                     "UserInfo.out"));  
             o.writeObject(userInfo);  
             o.close();  
         } catch (Exception e) {  
             // TODO: handle exception  
             e.printStackTrace();  
         }  
         try {  
             // 重新读取内容  
             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
                     "UserInfo.out"));  
             UserInfo readUserInfo = (UserInfo) in.readObject();  
             //读取后psw的内容为null  
             System.out.println(readUserInfo.toString());  
         } catch (Exception e) {  
             // TODO: handle exception  
             e.printStackTrace();  
         }  
     }  
 }  

被标记为transient的属性在对象被序列化的时候不会被保存。

接着回到ArrayList的分析中……

ArrayList的构造方法

看完属性看构造方法。ArrayList提供了三个构造方法:

/**
     * Constructs an empty list with the specified initial capacity.
     *
     * @param  initialCapacity  the initial capacity of the list
     * @throws IllegalArgumentException if the specified initial capacity
     *         is negative
     */
    public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
    }

    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        super();
        this.elementData = EMPTY_ELEMENTDATA;
    }

    /**
     * Constructs a list containing the elements of the specified
     * collection, in the order they are returned by the collection's
     * iterator.
     *
     * @param c the collection whose elements are to be placed into this list
     * @throws NullPointerException if the specified collection is null
     */
    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);
    }

第一个构造方法使用提供的initialCapacity来初始化elementData数组的大小。

第二个构造方法调用第一个构造方法并传入参数10,即默认elementData数组的大小为10。

第三个构造方法则将提供的集合转成数组返回给elementData(返回若不是Object[]将调用Arrays.copyOf方法将其转为Object[])。

ArrayList的其他方法:

trimToSize():

/**
     * Trims the capacity of this <tt>ArrayList</tt> instance to be the
     * list's current size.  An application can use this operation to minimize
     * the storage of an <tt>ArrayList</tt> instance.
     */
    public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = Arrays.copyOf(elementData, size);
        }
    }

trimToSize()的作用是节省内存空间,因为数组是恒长的,正常如果

int[] arr = new int[20];  //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

        不管数组里有意义的数有多少,arr数组一定占有20个 大小的内存,而ArrayList 则是变长的,因为ArrayList是先初始化一个长度为10 的数组,如果长度不够会自动扩容,这是很好的一个优点,但是有个小瑕疵,就是ArrayList每次扩容都会花费一定的开销,所以可以估计一下存储的数组大小,直接给出长度,当长度估计过大时,就可以使用这个trimToSize()方法,将没有用到的意义为空的数组的位置去除,可以节省空间。


add(E e)

add(E e)都知道是在尾部添加一个元素,源代码如下:

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }


    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == EMPTY_ELEMENTDATA) {   //判断elementData是否为空,若为空,则初始化为长度为10 的数组
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);// DEFAULT_CAPACITY=10

        }

        ensureExplicitCapacity(minCapacity);
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)//为true时,需要扩容
            grow(minCapacity);
    }

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
 
    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     */
    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;//ArrayList数组的最大长度为Integer.MaxValue= 0x7fffffff
    }

ArrayList是基于数组实现的,属性中也看到了数组,

   比如就这个添加元素的方法,如果数组足够大,则在将某个位置的值设置为指定元素即,如果数组容量不够了呢?

   看到add(E e)中先调用了ensureCapacityInternal(size+1)方法,之后将元素的索引赋给elementData[size],而后size自增。例如初次添加时,elementData[] 的长度为10,size为0,add将elementData[0]赋值为e,然后size设置为1(类似执行以下两条语句elementData[0]=e;size=1)。将元素的索引赋给elementData[size],会检查数组越界的情况,这里关键就在ensureExplicitCapacity(minCapacity)中了,该函数用来判断数组是否越界。如果数组长度超过现有的长度,则继续扩容,grow(minCapacity),每次扩容为原来的1.5倍,一直扩容到Integer.MaxValue的值,因为数组所以是Integer型,最大也就是Integer.MaxValue,所以ArrayList的最大长度是Integer.MaxValue+1(假如虚拟机的内存大小很大);

注意:容量的拓展将导致数组元素的复制,多次拓展容量将执行多次整个数组内容的复制。若提前能大致判断list的长度,最好提前估计数组长度并给予一个初始化数组长度,将有效的提高运行速度。可以理解提前分配好空间可以提高运行速度。

add(int index, E element) 

add(int index,E element)在指定位置插入元素。

public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
    //判断数组索引是否越界
     private void rangeCheckForAdd(int index) {
        if (index > size || index < 0)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

          首先调用rangeCheckForAdd()判断指定位置index是否超出elementData的界限,之后调用ensureCapacityInternal调整容量(若容量足够则不会拓展),然后调用System.arraycopy将elementData从index开始的size-index个元素复制到index+1至size-index的位置(即index开始的元素都向后移动一个位置),然后将index位置的值指向element。

addAll(Collection<? extends E> c)

addAll(Collection<? extends E> c) 按照指定 collection 的迭代器所返回的元素顺序,将该 collection 中的所有元素添加到此列表的尾部。

public boolean addAll(Collection<? extends E> c) {
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount
        System.arraycopy(a, 0, elementData, size, numNew);
        size += numNew;
        return numNew != 0;
    }

    先将集合c转换成数组,根据转换后数组的程度和ArrayList的size拓展容量,之后调用System.arraycopy方法复制元素到elementData的尾部,调整size。根据返回的内容分析,只要集合c的大小不为空,即转换后的数组长度不为0则返回true。

addAll(int index, Collection<? extends E> c) 

addAll(int index, Collection<? extends E> c) 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。

public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityInternal(size + numNew);  // Increments modCount

        int numMoved = size - index;
        if (numMoved > 0)
            //先将原数组后移numNew长度
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
                             
        //再将a数组复制到原数组的index到numNew的位置
        System.arraycopy(a, 0, elementData, index, numNew);
        size += numNew;
        return numNew != 0;
    }

      先判断index是否越界。然后判断容量大小是足够加入c ,不够则扩容。其他内容与addAll(Collection<
?
 extends E> c)基本一致,只是复制的时候先将index开始的元素向后移动index+numNew(numNew为c转为数组后的长度)个位置(也是一个复制的过程),之后将数组a内容复制到elementData的index位置至numNew。



clear()

clear()移除此列表中的所有元素。

 public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

        clear的时候并没有修改elementData的长度(好不容易申请、拓展来的,凭什么释放,留着搞不好还有用呢。这使得确定不再修改list内容之后最好调用trimToSize来释放掉一些空间),只是将所有元素置为null,size设置为0。

clone()

clone() 返回此 ArrayList 实例的浅表副本。

public Object clone() {//浅复制
        try {
            @SuppressWarnings("unchecked")
                ArrayList<E> v = (ArrayList<E>) super.clone();
                
           /*以使副本具有指定size的长度。对于在原数组和副本中都
             有效的所有索引,这两个数组将包含相同的值。即浅复制
           */
            v.elementData = Arrays.copyOf(elementData, size);
            
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError();
        }
    }

     调用父类的clone方法返回一个对象的副本,将返回对象的elementData数组的内容赋值为原对象elementData数组的内容,将副本的modCount设置为0。


contains(Object o) 

contains(Object o)   如果此列表中包含指定的元素,则返回 true。

    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    
    
    public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    
     public int lastIndexOf(Object o) {
        if (o == null) {
            for (int i = size-1; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = size-1; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

      indexOf方法返回值与0比较来判断对象是否在list中。接着看indexOf。
通过遍历elementData数组来判断对象是否在list中,若存在,返回index([0,size-1]),若不存在则返回-1。所以contains方法可以通过indexOf(Object)方法的返回值来判断对象是否被包含在list中。
既然看了indexOf(Object)方法,接着就看lastIndexOf,光看名字应该就明白了返回的是传入对象在elementData数组中最后出现的index值。采用了从后向前遍历element数组,若遇到Object则返回index值,若没有遇到,返回-1。


ensureCapacity(int minCapacity)

ensureCapacity(int minCapacity) 如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。

public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != EMPTY_ELEMENTDATA)
            // any size if real element table
            ? 0
            // larger than default for empty table. It's already supposed to be
            // at default size.
            : DEFAULT_CAPACITY;

        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }

get(int index)

get(int index) 返回此列表中指定位置上的元素。

 public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }
    
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
     @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

  RangeCheck检查一下是不是超出数组界限了,超出了就抛出IndexOutBoundsException异常。

indexOf(Object o)

indexOf(Object o)返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1。

public int indexOf(Object o) {
        if (o == null) {
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

isEmpty()

isEmpty()如果此列表中没有元素,则返回 true

 public boolean isEmpty() {
        return size == 0;
    }


remove(int index)

remove(int index)移除此列表中指定位置上的元素。

public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

    首先是检查范围,修改modCount,保留将要被移除的元素,将移除位置之后的元素向前挪动一个位置,将list末尾元素置空(null),返回被移除的元素。

remove(Object o)

remove(Object o)移除此列表中首次出现的指定元素(如果存在)。

    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;
    }
    
     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; // clear to let GC do its work
    }

      首先通过代码可以看到,当移除成功后返回true,否则返回false。remove(Object o)中通过遍历element寻找是否存在传入对象,一旦找到就调用fastRemove移除对象。为什么找到了元素就知道了index,不通过remove(index)来移除元素呢?因为fastRemove跳过了判断边界的处理,因为找到元素就相当于确定了index不会超过边界,而且fastRemove并不返回被移除的元素。下面是fastRemove的代码,基本和remove(index)一致。

removeRange(int fromIndex, int toIndex)

removeRange(int fromIndex, int toIndex)移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。

 protected void removeRange(int fromIndex, int toIndex) {
        modCount++;
        int numMoved = size - toIndex;
        System.arraycopy(elementData, toIndex, elementData, fromIndex,
                         numMoved);

        // clear to let GC do its work
        int newSize = size - (toIndex-fromIndex);
        for (int i = newSize; i < size; i++) {
            elementData[i] = null;
        }
        size = newSize;
    }

     执行过程是将elementData从toIndex位置开始的元素向前移动到fromIndex,然后将newNum位置之后的元素全部置空顺便修改size。

注意:这个方法是protected

先看下面这个例子

ArrayList<Integer> ints = new ArrayList<Integer>(Arrays.asList(0, 1, 2,3, 4, 5, 6));  
         // fromIndex low endpoint (inclusive) of the subList  
         // toIndex high endpoint (exclusive) of the subList  
        ints.subList(2, 4).clear();  
         System.out.println(ints);

     输出结果是[0, 1, 4, 5, 6],结果是不是像调用了removeRange(int fromIndex,int toIndex)!效果相同


set(int index, E element) 

set(int index, E element) 用指定的元素替代此列表中指定位置上的元素。

public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

首先检查范围,用新元素替换旧元素并返回旧元素。


size()

size()返回此列表中的元素数。

public int size() {
        //根据modCount判断检查正在读取长度时有没有正在修改数组的操作
        checkForComodification();
        return this.size;
    }
        
    private void checkForComodification() {
        if (ArrayList.this.modCount != this.modCount)
            throw new ConcurrentModificationException();
    }

 toArray() 

 toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。

public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }

    调用Arrays.copyOf将返回一个数组,数组内容是size个elementData的元素,即拷贝elementData从0至size-1位置的元素到新数组并返回。

toArray(T[] a)

toArray(T[] a)按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组;返回数组的运行时类型是指定数组的运行时类型。

 @SuppressWarnings("unchecked")
    public <T> T[] toArray(T[] a) {
        if (a.length < size)
            // Make a new array of a's runtime type, but my contents:
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
        System.arraycopy(elementData, 0, a, 0, size);
        if (a.length > size)
            a[size] = null;
        return a;
    }

     如果传入数组的长度小于size,返回一个新的数组,大小为size,类型与传入数组相同。所传入数组长度与size相等,则将elementData从0开始到size-1复制到传入数组a中并返回传入的数组。若传入数组长度大于size,除了复制elementData外,还将把返回数组的第size个元素置为空。

subList(int fromIndex, int toIndex)

subList(int fromIndex, int toIndex)  是从写了java.util.List接口的方法:

public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
    }
/*      其中,AbstractList<E>此类提供 List 接口的骨干实现,以最大
    限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作
    。对于连续的访问数据(如链表),应优先使用 AbstractSequentialList,
    而不是此类。 要实现不可修改的列表,编程人员只需扩展此类,并提供
    get(int) 和 size() 方法的实现。 要实现可修改的列表,编程人员必须另
    外重写 set(int, E) 方法(否则将抛出 UnsupportedOperationException)。
    如果列表为可变大小,则编程人员必须另外重写 add(int, E) 和 remove(int) 方法。
*/

 private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }

        public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

        protected void removeRange(int fromIndex, int toIndex) {
            checkForComodification();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }

        public boolean addAll(Collection<? extends E> c) {
            return addAll(this.size, c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
            int cSize = c.size();
            if (cSize==0)
                return false;

            checkForComodification();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }
//迭代器,实现了这个方法就可成为foreach()的循环对象
        public Iterator<E> iterator() {
            return listIterator();
        }

        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;

            return new ListIterator<E>() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;

                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }

                @SuppressWarnings("unchecked")
                public E next() {
                    checkForComodification();
                    int i = cursor;
                    if (i >= SubList.this.size)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i + 1;
                    return (E) elementData[offset + (lastRet = i)];
                }

                public boolean hasPrevious() {
                    return cursor != 0;
                }

                @SuppressWarnings("unchecked")
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }

                public int nextIndex() {
                    return cursor;
                }

                public int previousIndex() {
                    return cursor - 1;
                }

                public void remove() {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        SubList.this.remove(lastRet);
                        cursor = lastRet;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void add(E e) {
                    checkForComodification();

                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                final void checkForComodification() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
            };
        }

      其中,AbstractList<E>此类提供 List 接口的骨干实现,以最大限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作  。对于连续的访问数据(如链表),应优先使用 AbstractSequentialList,而不是此类。 要实现不可修改的列表,编程人员只需扩展此类,并提供 get(int) 和 size() 方法的实现。 要实现可修改的列表,编程人员必须另外重写 set(int, E) 方法(否则将抛出 UnsupportedOperationException)。 如果列表为可变大小,则编程人员必须另外重写 add(int, E) 和 remove(int) 方法。


iterator()

iterator()重写了从java.util.List继承的方法

    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

listIterator()

listIterator()  重写了从java.util.List继承的方法

    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }
    
    public ListIterator<E> listIterator(int index) {
        if (index < 0 || index > size)
            throw new IndexOutOfBoundsException("Index: "+index);
        return new ListItr(index);
    }
    
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

注意:

listIterator()  和iterator() 的区别在于:

iterator() 遍历只能向下遍历,而listIterator() 遍历,不仅可以向下遍历,还可以向上遍历






    原文作者:java集合源码分析
    原文地址: https://blog.csdn.net/wangnanwlw/article/details/52515366
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞