JDK源码阅读之AbstractList

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/BlingZeng/article/details/83147069

AbstractList概述

概述来自jdk的api:

此类提供 List接口的骨干实现,以最大限度地减少实现“随机访问”数据存储(如数组)支持的该接口所需的工作。对于连续的访问数据(如链表),应优先使用
AbstractSequentialList,而不是此类。

要实现不可修改的列表,编程人员只需扩展此类,并提供 get(int) 和 size() 方法的实现。

要实现可修改的列表,编程人员必须另外重写 set(int, E) 方法(否则将抛出 UnsupportedOperationException)。如果列表为可变大小,则编程人员必须另外重写 add(int, E) 和remove(int) 方法。

AbstractList类图

AbstractList类图
AbstractList 继承自 AbstractCollection 抽象类,实现了 List 接口 ,是 ArrayList 和 AbstractSequentiaList 的父类。

AbstractList的两个内部迭代器

Iterator 迭代器

private class Itr implements Iterator<E> {
        /**
         * 游标
         */
        int cursor = 0;

        /**
         * 上一次迭代到的元素的位置,每次使用完就会置为 -1
         */
        int lastRet = -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();
            }
        }

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

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                // 每次使用完就会置为 -1
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

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

这是一个简单的Iterator的实现类,主要实现了next,remove等方法,还有判断是否有并发操作。

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);
                // 游标在这个时候会重合
                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();
            }
        }
    }

ListIterator迭代器是在Iterator迭代器上扩展的,增加了add,set,previous等重要方法,提过了更多的迭代方式。
阅读到这里的时候我看源码,ListIterator的add,set方法都是调用集合的add,set方法,那么这两个方法是不是就有些多余了?
答:其实不然,因为我们在使用迭代器迭代集合的时候,可能会有需要操作集合,如果使用集合的方法来操作集合,那么就会有并发的错误。所以ListIterator添加了add,set等方法就解决了这个问题。

AbstractList的重要方法

AbstractList是不支持修改的,所以他对于修改的方法是直接抛出错误的。

AbstractList不支持的方法

 public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

     public E remove(int index) {
        throw new UnsupportedOperationException();
    }

索引方法

public int indexOf(Object o) {
        ListIterator<E> it = listIterator();
        if (o==null) {
            while (it.hasNext())
                if (it.next()==null)
                    return it.previousIndex();
        } else {
            while (it.hasNext())
                if (o.equals(it.next()))
                    return it.previousIndex();
        }
        return -1;
    }

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

我们从源代码中可以看到,无论是正索引还是反索引,使用的都是ListIterator迭代器。
并且都是有对null值的查询,因此在这里可以看出,List的值是可以为空的。

equals

public boolean equals(Object o) {
        if (o == this)
            return true;
        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());
    }

AbstractList的equals方式也是重写了的,与String类方法一致。会去比较元素,如果全部元素相同,那么也会判断相同。

AbstractList的两个内部类

SubList

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

在源码中我们可以看到SubList是继承AbstractList,并且SubList的全部方法都是使用AbstractList的,所以这个类就是AbstractList的一个包装类。

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,这个类就是在Sublist类上添加了一个接口RandomAccess,表示这个类可以支持快速访问

AbstractList源码阅读感受

这个类的代码其实还是很好阅读的,最起码是简单的,没有涉及什么高深的算法。AbstractList内部有两个迭代器,两个内部类,而且都是一层继承一层的。这种设计我觉得代码看起来会比较舒服。

说明

本文是本人撰写,如果阅读本人你有些许收获,那是我的荣幸。如果有错误或者不同意见,欢迎留言或者联系我:[email protected]

猜你喜欢

转载自blog.csdn.net/BlingZeng/article/details/83147069
今日推荐