java.util.ArrayList学习笔记(二)

来源:互联网 发布:剑桥少儿英语网络课程 编辑:程序博客网 时间:2024/05/16 11:21

本文接java.util.ArrayList学习笔记(一)

public ListIterator<E> listIterator(int index) {    if (index < 0 || index > size)        throw new IndexOutOfBoundsException("Index: "+index);    return new ListItr(index);}

获取由指定位置开始的列表迭代器。即,用户第一次调用迭代器的next()方法返回的是列表中下标为index的元素。但是迭代器的调用方仍然可以使用本迭代器进行列表中元素的遍历。在这里需要特别注意列表迭代器游标的有效位置为:0 ~ size。当 index = size时,则代表列表迭代器的初始游标在列表的末尾,其next()方法将返回null或者抛出异常,一般可以用于逆向遍历列表。

public ListIterator<E> listIterator()

返回一个从列表头部开始的列表迭代器,其内部实现采用的是:listIterator(0)

public Iterator<E> iterator()

返回一个从列表头部开始的基本迭代器。

public List<E> subList(int fromIndex, int toIndex)

返回当前列表的一个子列表。其中元素共享,即:在子列表中发生的修改会直接反映到初始列表中,反之亦然。

私有内部类


基础迭代器(Itr)


参数介绍


int cursor

迭代器当前的游标。迭代器的游标代表的为:当调用next()方法时,返回的列表元素的下标。

int lastRet = -1

最后一次调用next()方法返回的元素的下标。默认为-1。

int expectedModCount = modCount

迭代器创建时,列表对象瞬态的可能的结构变化次数,主要用于检测是否存在并发修改,从而导致并发错误。

方法介绍


public boolean hasNext()

判断当前迭代器调用next()方法是否还有有效元素返回。当列表的游标已经达到列表末尾时,即:cursor == size时候,则返回false,否则返回true。

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];}

返回当前迭代器正向遍历的下一个元素。注意,本算法中有两次并发结构修改检测,分别是,强校验:方法开始时,调用checkForComodification进行结构性修改次数检测;弱校验:如果当前游标的位置高于列表的容量,产生情形为:列表发生元素的删除操作,并调用了trimToSize来降低列表的空间占用。在成功完成校验后,需要交迭代器游标后移,并将最后一次访问的元素的坐标设定为访问元素的下标。

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();    }}

删除列表迭代器刚刚访问的元素。当迭代器并没有访问任何元素,或者刚刚访问的元素已经被删除时,其内部基于ArrayList.this.remove()实现。在完成删除后,需要将迭代器游标前移,将最后一次访问元素的下标置为-1,并对迭代器中结构性修改次数进行更新。

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

检测除持有本迭代器的线程外,是否有潜在的并发修改冲突。其基本原理是检测列表对象的

列表迭代器(ListItr)


继承结构


这里写图片描述

方法介绍


具体方法说明,请参见:java.util.ListIterator学习笔记。
其内部基本基于ArrayList中的方法实现。在进行元素访问操作时,均会进行同步修改校验。

子列表(SubList)


构造方法

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;}

由构造方法,我们可以看出:子列表持有的并不是父亲列表中元素的复制,而是直接维持一个父亲列表的引用,因此子列表对其中元素的修改会直接影响到父亲列表,甚至是根列表,反之亦然。并且,子列表的结构修改次数是与根列表的相同,用于检测并发的修改冲突。

基本属性


private final AbstractList<E> parent;

代表当前子列表的直接父亲列表。即:列表3是列表2的子列表,列表2为列表1的子列表,则在列表3中,parent指向的是列表2。

private final int parentOffset;

当前子列表相对于直接父亲列表的元素偏移量。即:列表3相对于列表2的元素偏移量。

private final int offset;

当前子列表相对于根列表的元素偏移量,即:列表3相对于列表1的元素偏移量。

int size;

当前子列表的长度。

注:对于子列表的接口说明,可以参见java.util.AbstractList学习笔记。在ArrayList的实现中,通过数组的下标和数组的copyOf函数实现subList的所有功能。其实现的逻辑与ArrayList本身的实现逻辑大体相同,在此不做赘述。

0 0