JAVA集合源码攻坚战(6)——AbstractList

前言

前面我们已经分析过AbstractCollection和List这两个接口类了,接下来分析AbstractList。

AbstractList的父母

刚刚灵光一闪,想到一个不太恰当的比喻。比如AbstractList,继承了AbstractCollection,实现了List接口,那么AbstractCollection相当于是父亲,子承父业,List相当于母亲,百善孝为先,应该实现母亲的愿望(方法)。

子承父业

首先在AbstractCollection中,我们提过,AbstractCollection要求它的实现类一定要Iterator()和size()方法。而在AbstractList中,已经实现了它的Iterator()方法

public Iterator<E> iterator() {
        return new Itr(); // Itr类是自己实现的
    }

然后AbstractList还自己定义了一个抽象方法

abstract public E get(int index);

从这里其实就可以看出,get这个方法能根据索引index来返回元素,奠定了List这一系列里,他的实现类都是有序的,能根据索引来查找元素。
另外,要实现一个不可修改的列表,程序员只需要扩展这个类并提供get(int)和size()方法的实现。
要实现可修改的列表,程序员必须另外覆盖set(int, E)方法(否则会抛出一个UnsupportedOperationException)。 如果列表是可变大小,则程序员必须另外覆盖add(int, E)和remove(int)方法。

实现的方法

1、public int indexOf(Object o)
从头开始查找指定元素首次出现的位置

    public int indexOf(Object o) {
    	// 获取一个list迭代器,因为使用默认构造器,当前游标位置为起始位置0,也即从前往后遍历
        ListIterator<E> it = listIterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return it.previousIndex();
        } else {
            while (it.hasNext())
            	// 利用equals方法来进行比较
                if (o.equals(it.next()))
                    return it.previousIndex();
        }
        return -1;
    }

注意,这里的迭代器listIterator是AbstractList自己实现的,我们后面再详细分析。同时,要注意游标并不是直接指向元素的,而是位于元素之间,实际当循环中的if语句匹配成功时,游标已经在我们要找的那个元素后面了,所以需要返回的是前一个游标的位置。
2、public int lastIndexOf(Object o)
从后往前遍历查找指定元素首次出现的位置

public int lastIndexOf(Object o) {
    	// 获取一个游标位置从末尾开始的迭代器,使用有参数的构造器
        ListIterator<E> it = listIterator(size());
        if (o==null) {
            while (it.hasPrevious())
                if (it.previous()==null)
                    return it.nextIndex();
        } else {
            while (it.hasPrevious())
                if (o.equals(it.previous()))
                    return it.nextIndex();
        }
        return -1;
    }

3、
public void clear() 清除元素
protected void removeRange(int fromIndex, int toIndex) 范围删除元素

public void clear() {
        removeRange(0, size());
    }

protected void removeRange(int fromIndex, int toIndex) { // 删除包含fromIndex,不包含toIndex的范围内的元素
		// 获取一个游标位于fromIndex元素之前的迭代器
        ListIterator<E> it = listIterator(fromIndex);
        for (int i=0, n=toIndex-fromIndex; i<n; i++) { // 通过i<n判断,不会删除toIndex该位置的元素
            it.next();
            it.remove();
        }
    }

4、public boolean addAll(int index, Collection<? extends E> c)
在指定的索引位置添加元素,添加的元素顺序按照给定的集合的迭代器返回元素顺序

public boolean addAll(int index, Collection<? extends E> c) {
    	// 索引越界检查
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
        	// 需要重写add(E)和add(index,E)方法,否则抛出UnsupportedOperationException异常
            add(index++, e);
            modified = true;
        }
        return modified;
    }
private void rangeCheckForAdd(int index) {
        if (index < 0 || index > size())
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

5、public boolean equals(Object o)
重写了equals方法

在这里插入代码片

迭代器

AbstractList自己内部实现了两个迭代器:Itr和ListItr。
ListItr本身也是继承了Itr的。我们先来看Itr

Itr迭代器

先来看完整的实现代码

    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         * 指向后续调用next()方法返回的那个元素的索引
         */
        int cursor = 0;

        /**
         * Index of element returned by most recent call to next or
         * previous.  Reset to -1 if this element is deleted by a call
         * to remove.
         * 指向最近一次调用next或previous方法返回的元素的索引。如果该元素被删除了,则重置为-1。
         */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         * modCount这个变量是后续的list实现类应该有的。如果违反了这一点,迭代器会出现并发的修改操作。
         */
        int expectedModCount = modCount;

        // 实现了Iterator接口的hasNext方法
        public boolean hasNext() {
            return cursor != size();
        }

        // 实现了Iterator接口的next方法
        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();
            }
        }

        // 实现了Iterator接口的remove方法
        // 根据Iterator对remove的描述,该方法应该只有在调用过一次next方法后,才能调用该方法。
        public void remove() {
        	// 如果lastRet<0,说明之前并没有调用过next,或者已经被移除,直接抛出异常。
            if (lastRet < 0)
                throw new IllegalStateException();
            // 检查是否有并发操作
            checkForComodification();

            try {
            	// 调用AbstractList的子类实现的remove(index)方法
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)// 如果删除的元素的索引在当前游标前面,那么删除元素后,游标要向前移动一个单位
                    cursor--;
                lastRet = -1;// 重置为-1
                expectedModCount = modCount;	// 一个修改操作结束后,重新设定检查并发的参数的值。
                								//其实这是避免子类实现了其他方法,会修改modCount值,
                								//造成expectedModCount与modCount不一致
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
        
        // 检查并发修改操作
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

ListItr迭代器

    // 继承Itr,实现了ListIterator,是对Itr的一个增强版
    // ListItr 实现了ListIterator,支持双向遍历
    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);	// 调用子类的get(index)方法
                lastRet = cursor = i;	// 返回刚刚查询的那个元素的索引
                return previous;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }

        public int nextIndex() {
            return cursor;
        }

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

        // 和remove类似,
        // 根据ListIterator对set的描述,该方法应该只有在调用过一次next或者previous后,才能调用该方法。
        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();	// 检查并发操作

            try {
            	// 调用实现类的set(index,E)方法
                AbstractList.this.set(lastRet, e);
                expectedModCount = modCount;	// 操作记录数设置
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

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

            try {
                int i = cursor;
                // 在当前游标位置,调用子类的add方法插入元素
                AbstractList.this.add(i, e);
                lastRet = -1;	// 重置lastRet
                cursor = i + 1;	// 插入元素后,游标位置向后移动一位
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

两个内部类

AbstractList定义了两个内部类SubList和RandomAccessSubList
我们先来看SubList

SubList

SubList本身是继承了AbstractList的,下面看源码:

class SubList<E> extends AbstractList<E> {
	// 根据给出的构造器,该参数指向整个完整的List,而不是表示SubList这个子集
    private final AbstractList<E> l;
    // 子集对父集合的一个偏移量,
    private final int offset;
    // 子集的大小
    private int size;

    // 构造函数,截取传入的List的一部分
    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();
        // 实质上还是调用AbstractList的方法对原集合进行操作,无非就是索引位置要额外加上偏移量
        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();
    }
}

源码看上去很长,很多,其实重点就是在开头我注释的部分,下面很多都是大同小异,无非就是实现了一些操作或者边界检查。
可以看出,SubList基本所有操作,都还是依赖于AbstractList来实现的,而且,我们在前面说过,List的subList操作,其实是保持了对原list的引用的,如果通过调用subList方法获得的list集合,进行了某些操作,其实也是对原集合进行操作,这点需要格外注意。

另一个内部类RandomAccessSubList

RandomAccessSubList是继承了SubList,实现了RandomAccess接口
这里出现了一个RandomAccess接口,我们去看它的源码

/**
 * Marker interface used by <tt>List</tt> implementations to indicate that
 * they support fast (generally constant time) random access.  The primary
 * purpose of this interface is to allow generic algorithms to alter their
 * behavior to provide good performance when applied to either random or
 * sequential access lists.
 *
 * <p>The best algorithms for manipulating random access lists (such as
 * <tt>ArrayList</tt>) can produce quadratic behavior when applied to
 * sequential access lists (such as <tt>LinkedList</tt>).  Generic list
 * algorithms are encouraged to check whether the given list is an
 * <tt>instanceof</tt> this interface before applying an algorithm that would
 * provide poor performance if it were applied to a sequential access list,
 * and to alter their behavior if necessary to guarantee acceptable
 * performance.
 *
 * <p>It is recognized that the distinction between random and sequential
 * access is often fuzzy.  For example, some <tt>List</tt> implementations
 * provide asymptotically linear access times if they get huge, but constant
 * access times in practice.  Such a <tt>List</tt> implementation
 * should generally implement this interface.  As a rule of thumb, a
 * <tt>List</tt> implementation should implement this interface if,
 * for typical instances of the class, this loop:
 * <pre>
 *     for (int i=0, n=list.size(); i &lt; n; i++)
 *         list.get(i);
 * </pre>
 * runs faster than this loop:
 * <pre>
 *     for (Iterator i=list.iterator(); i.hasNext(); )
 *         i.next();
 * </pre>
 *
 * <p>This interface is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @since 1.4
 */
public interface RandomAccess {
}

根据文档解释,实际上就是一个支持快速随机访问的标识。一般有该标识的list类,遍历的时候,采用普通for循环的性能要比采用迭代器好。
再来看RandomAccessSubList

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

无非就是在SubList的基础上加了个RandomAccess标识,表明它支持随机访问。

剩下的方法

如果你也是对着源码在看,可以发现,还有几个方法没有讲到。
1、public List subList(int fromIndex, int toIndex)
AbstractList实现的subList方法

public List<E> subList(int fromIndex, int toIndex) {
        return (this instanceof RandomAccess ?
                new RandomAccessSubList<>(this, fromIndex, toIndex) :
                new SubList<>(this, fromIndex, toIndex));
    }

因为涉及到两个内部类,所以放到后面来分析。
这里多了个判断,会判断当前的这个list,是否是RandomAccess或其子类的实例对象,其实就是为了区分是否支持随机访问。

2、public boolean equals(Object o)
重写了Object的equals方法

public boolean equals(Object o) {
        if (o == this)
            return true;
        // 在运行时判断是否是List或其子类的实例对象,如果不是,直接false
        if (!(o instanceof List))
            return false;

        ListIterator<E> e1 = listIterator();	// 获得当前对象的迭代器
        ListIterator<?> e2 = ((List<?>) o).listIterator();	// 获得参数对象的迭代器
        while (e1.hasNext() && e2.hasNext()) {
            E o1 = e1.next();
            Object o2 = e2.next();
            if (!(o1==null ? o2==null : o1.equals(o2)))
                return false;
        }
        return !(e1.hasNext() || e2.hasNext());
    }

只有两个都是List或其子类的数据类型,然后判断是否包含相同的元素,且顺序一致,才能返回true。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值