Collection容器家族(AbstractList超类和AbstractSequentialList超类)

AbstractList超类

一、在Collection容器集合中的位置及作用

        Collection集合体系有两大分支,一个是List分支、另一个是Set分支,Collection是这两大分支超类;这两个分支都由接口去约束,每个几口都有其实现类,而AbstractList抽象类就是List分支的顶层超类。此类提供了List接口的骨干实现,以最大限度地减少实现由“随机访问”数据存储(例如数组、链表)支持的此接口所需的工作量。此类是针对线性表结构。

二、源码功能及实现

抽象方法 (作为抽象类,但是它只有一个抽象方法)

    /**
     * 功能:根据索引获取集合元素
     * 实现:
     * 1.该方法作为抽象类的唯一抽象方法,需要之类去实现
     * 注:如果是数组的线性表那么定位下标即可,如果是链表迭代才行,这里就没具体规定
     */
    abstract public E get(int index);

非抽象方法

1.添加元素 add(E e)、add(int index,  E element) ---未实现

    /**
     * 功能:添加元素
     * 实现:
     * 1.调用add(int index, E element)方法在集合末尾处添加元素
     * 注:add(int index, E element)方法并没有被此类实现
     */
    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    /**
     * 功能:在集合指定索引位置添加元素
     * 实现:此抽象类没有实现
     */
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

        没有实现是因为List集合存储的数据结构不同,如数组和链表;所以超类无法实现具体的添加功能,有具体子类实现。

2.替换指定索引位置的元素 set(int index, Eelement) ---未实现

    /**
     * 功能:替换指定索引位置的元素
     * 实现:此抽象类没有实现
     * 注:没有实现原因是因为子类的存储结构未知
     */
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

 3.删除指定所引处的元素 remove(int index) ---未实现

    /**
     * 功能:删除指定所引处的元素
     * 实现:此抽象类未实现
     * 注:未实现
     */
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

  凡是涉及到与数据存储结构有关的方法均不能实现

4.继承自父类的迭代器 iterator()

    /**
     * 功能:获取迭代器
     * 实现:
     * 1.通过匿名内部类实现迭代器,创建迭代器Iterator实现类并返回
     */
    public Iterator<E> iterator() {
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to 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.
         */
        /**
         *最近一次调用返回到下一个或上一个的元素索引。 如果通过删除调用删除此元素,则重置为-1。
         * 通俗点说,他保存cursor操作前的索引
         */
        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值。 如果违反了此期望,则迭代器已检测到并发修改。
         */
        int expectedModCount = modCount;

        /**
         * 功能:检查是否还有下一个元素
         * 实现:
         * 1.迭代器每次迭代出一个元素时元素索引指针cursor都会下移
         * 2.通过检查元素指针cursor是否等于集合长度判断时候还有元素
         */
        public boolean hasNext() {
            return cursor != size();
        }

        /**
         * 功能:获取当前元素索引指针(cursor)处的元素
         * 实现:
         * 1.检测是否发生并发修改,并发修改则抛出异常
         * 2.获取当前元素索引指针所指向的元素,保存当前索引到lastRet、cursor++
         * 3.返回回去到的元素
         */
        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();
            }
        }

        /**
         * 功能:删除lastRet索引处的元素
         * 实现:
         * 1.对lastRet进行和是否并发修改进行检查
         * 2.调用AbstractList超类的remove方法删除lastRet索引处的元素
         * 3.如果元素索引指针cursor大于lastRet,则将cursor迁移一位,lastRet置为-1
         */
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }

        /**
         * 功能:检查是否发生并发修改
         * 实现:
         * 1.通过modCount和expectedModCount是否相等检查
         */
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

5.List集合特有的迭代器 listIterator()

    /**
     * 功能:List特有迭代器
     * 实现:调用listIterator(final int index)获取迭代器
     * 注:每次调用,迭代器都能从头开始
     */
    public ListIterator<E> listIterator() {
        return listIterator(0);
    }

    /**
     * 功能:获取List集合特有迭代器
     * 实现:
     * 1.检查索引范围无误后创建并返回迭代器实现类对象
     */
    public ListIterator<E> listIterator(final int index) {
        rangeCheckForAdd(index);

        return new ListItr(index);
    }

    private class ListItr extends Itr implements ListIterator<E> {
        /**
         * ListItr类有参构造器,初始化开始元素索引指针位置
         */
        ListItr(int index) {
            cursor = index;
        }

        /**
         * 功能:检查cursor指针前面是否还有元素
         * 实现:
         * 1.通过cursor是否等于0判断
         */
        public boolean hasPrevious() {
            return cursor != 0;
        }

        /**
         * 功能:获取前一个元素
         * 实现:
         * 1.检查是否发生并发操作,是则抛异常
         * 2.将现在cursor向前移动一位,获取元素并返回
         */
        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;
        }

        /**
         * 功能:替换元素
         * 实现:
         * 1.检查lastRet是否越界,检查时候并发操作
         * 2.调用AbstractList的set方法进行替换
         */
        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();
            }
        }

        /**
         * 功能:添加元素
         * 实现:
         * 1.检查是否并发操作,是则抛异常
         * 2.调用AbstractList的add方法进行添加操作,并将元素指针索引 + 1
         */
        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();
            }
        }
    }

6.获取集合第一次出现指定元素的索引 indexOf(Object o)

    /**
     * 功能:获取集合第一次出现的指定元素的索引
     * 实现:
     * 1.获取List集合特有迭代器listIterator
     * 2.如果待查找参数为null,遍历集合找到第一个为null的元素并返回,如果没找到返回-1
     * 3.如果待查找参数不为null,遍历集合使用equals方法找到第一个相同元素并返回,没有返回-1
     */
    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;
    }

7.回去集合最后一次出现指定元素的索引 lastIndexOf(Object c)

    /**
     * 功能:获取集合最后一次出现指定元素的索引
     * 实现:
     * 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;
    }

8.删除集合所有元素 clear()、删除集合指定范围内的所有元素removeRange(int fromIndex, int toIndex)

     * 功能:删除集合的所有元素
     * 实现:
     * 1.调用removeRange方法删除集合整个范围内的所有元素
     */
    public void clear() {
        removeRange(0, size());
    }

    /**
     * 功能:删除指定范围内的所有元素
     * 实现:
     * 1.通过特有迭代器获取fromIndex索引处开始到结尾的所有元素
     * 2.通过for循环,逐个删除元素
     */
    protected void removeRange(int fromIndex, int toIndex) {
        ListIterator<E> it = listIterator(fromIndex);
        for (int i=0, n=toIndex-fromIndex; i<n; i++) {
            it.next();
            it.remove();
        }
    }

9.在指定位置添加一个集合的元素 addAll(int index, Collection<? extends E> c)

    /**
     * 功能:在指定位置添加一个集合的元素
     * 实现:
     * 1.检查是否并发操作
     * 2.遍历参数集合并调用add(int index, E e)方法进行这个添加,每次添加后索引+1
     */
    public boolean addAll(int index, Collection<? extends E> c) {
        rangeCheckForAdd(index);
        boolean modified = false;
        for (E e : c) {
            add(index++, e);
            modified = true;
        }
        return modified;
    }

10.AbstractList的subList(int froIndex, int toIndex)方法和SubList类

        AbstractList超类的subList的方法使用方法类似于String类的subString功能一样,都是用来切割用的。但是它们两者还是有微小的区别。在功能使用上就对比于subString方法就ke可以。

     我们看一看SubList类是怎么做的,主要看一下构造器,这个list引用现在就是我们原 集合,它把自己的属性域”AbstractList<E> l “指向了原来的集合。SubList类对“l”进行改变结构,改变值的操作,也直接的去改变了原来的集合值或者是结构。这使我们在使用subList的时候必须慎重考虑的一点。

        下属代码是对上述结论的测试:

    @Test
    public void test3() {
        AbstractList abstractList = new ArrayList<String>();
        abstractList.add("a");
        abstractList.add("b");
        abstractList.add("c");
        abstractList.add("d");
        abstractList.add("e");
        System.out.println("原始集合:          " + abstractList.toString());

        List subList = abstractList.subList(1, 3);

        System.out.println("截取后集合:        " + subList);
        System.out.println("截取后原始集合:    " + abstractList);
        subList.add("我是后添加数据f");
        System.out.println("添加元素后原始集合:" + abstractList);
        System.out.println("截取后集合:        " + subList);
    }

        显然SubList能改变原集合的值,所以我们在使用时要慎重,如果不想改变原集合的值,那么我们就要把这个subList保存到另一个集合中使用它。AbstractList还有一个类叫做RandomAccessSubList,继承了SubList,实现了RandomAccess接口,实现这个接口其目的也就是为了能在执行Collections下的binarySearch中调用indexedBinarySearch方法,如果没有实现RandomAccess就只能调用iteratorBinarySearch方法。两种方法的速度是不一样的。

11.比较方法equals(Object o)和获取hash值算法hashCode()详解

    /**
     * 功能:比较两个集合是否完全相等(大小和所有元素相同且顺序也相同)
     * 实现:
     * 1.判断参数集合是不是本身,是则返回true;判断是否是List,不是直接返回false
     * 2.获取自身迭代器,获取参数集合迭代器
     * 3.获取每个列表相同位置的元素进行比较,只要有一个位置的元素不同,就返回false
     * 4.最后看看每个列表尾部是否形同
     */
    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());
    }

    /**
     * 功能:获取该集合的hash值
     * 实现:
     * 1.遍历集合,将每个元素的hash值累加
     * 注:为了保证避免出现相同的值前面加31作为系数
     */
    public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

        这个问题之前我也很好奇,不过最后还是在书上得到了比较明朗的解释,当然这个问题主要是针对映射相关的操作(Map接口)。学过数据结构的同学都知道Map接口的类会使用到键对象的哈希码,当我们调用put方法或者get方法对Map容器进行操作时,都是根据键对象的哈希码来计算存储位置的,因此如果我们对哈希码的获取没有相关保证,就可能会得不到预期的结果。在java中,我们可以使用hashCode()来获取对象的哈希码,其值就是对象的存储地址,这个方法在Object类中声明,因此所有的子类都含有该方法。那我们先来认识一下hashCode()这个方法吧。hashCode的意思就是散列码,也就是哈希码,是由对象导出的一个整型值,散列码是没有规律的,如果x与y是两个不同的对象,那么x.hashCode()与y.hashCode()基本是不会相同的。

AbstractSequentialList超类

一、在Collection集合中的位置及作用

    AbstractSequentialList继承了AbstractList,它是一个基于迭代器的抽象类,它只实现了最基本的增删改查方法,其中的所有的方法都需要根据迭代器来实现。能看出如果继承这个类,那么一定是和链表相关的类,如果是数组的话,也不能用效率这么低的Iterator来实现增删改查。

    作为LinkedList的父类,它的基本实现给予了LinkedList一个很好的发挥空间。那么我们来看看AbstractSequentialList都有哪些方法。

2.源码方法和实现

抽象方法:

    public abstract ListIterator<E> listIterator(int index);

        AbstractSequentialList只有一个抽象方法,那就是listIterator,而它的iterator方法返回的是一个ListIterator对象。也就是说LinkedList就是基于ListIterator这个双向迭代器来实现的。这里我们回顾一下,双向迭代器是可以修改原集合中的内容的。

非抽象方法:

1.get方法,通过双向迭代器返回集合中元素

    public E get(int index) {
        try {
            return listIterator(index).next();
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

2.set方法 通过迭代器设置集合中的元素

    public E set(int index, E element) {
        try {
            ListIterator<E> e = listIterator(index);
            E oldVal = e.next();
            e.set(element);
            return oldVal;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

 3.add方法  通过迭代器添加一个元素

    public void add(int index, E element) {
        try {
            listIterator(index).add(element);
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

4.remove方法 通过迭代器将固定位置的元素拿到集合外面

    public E remove(int index) {
        try {
            ListIterator<E> e = listIterator(index);
            E outCast = e.next();
            e.remove();
            return outCast;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

5.addAll方法 通过迭代器在固定位置添加一个集合的元素

    public boolean addAll(int index, Collection<? extends E> c) {
        try {
            boolean modified = false;
            ListIterator<E> e1 = listIterator(index);
            Iterator<? extends E> e2 = c.iterator();
            while (e2.hasNext()) {
                e1.add(e2.next());
                modified = true;
            }
            return modified;
        } catch (NoSuchElementException exc) {
            throw new IndexOutOfBoundsException("Index: "+index);
        }
    }

 6.Iterator方法 返回的是一个listIterator对象

    public Iterator<E> iterator() {
        return listIterator();
    }

三、AbstractSequentialList总结

        AbstractSequentialList超类的对集合的增删改查操作都是基于迭代器完成的(包括get方法)。AbstractSequentialList可以这么讲,他是一个按次序访问的线性表的简化版,它是一个超类,他规定了其子类必须去实现ListIterator这个接口。必须用迭代的方式完成对线性表的各项操作。当我们在使用AbstractSequentialList的子类对象时,遍历操作最好是使用迭代器,因为for循环的get也是使用迭代器所以我们不要多此一举再去增加个for循环调用迭代方法了。

总结:

       AbstractList,AbstractSequentialList基本上内容也就是这些,至于为什么这么设计,以我浅显的修为来看,其实如果直接从AbstractList延伸出ArrayList和LinkedList也未尝不可。但是既然这么设计了,我觉得它的好处可能是在于AbstractList支持RandomAccess,而我们的链表实现的线性表跟这种随机访问根本不搭边,不如再次由AbstractList特化出一个只针对于链表的超类,这样在定义LinkedList就有一个绝对的定位,它就是一个纯次序访问的链表集合,不允许有歧义和瑕疵。

        这样层次分明,定位清楚,不但是开发方便,我们使用理解起来也比较方便。

posted @ 2018-08-20 14:50  小情绪Ango  阅读(137)  评论(0编辑  收藏  举报