zoukankan      html  css  js  c++  java
  • 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就有一个绝对的定位,它就是一个纯次序访问的链表集合,不允许有歧义和瑕疵。

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

  • 相关阅读:
    合并两个排序的链表
    反转链表
    java网络编程之TCP通讯
    java网络编程之UDP通讯
    Java中的线程同步机制
    阿里研发工程师面试题三个小结
    Android开发的进阶之路
    获取一个字符串中每一个字母出现的次数使用map集合
    Android常见面试题目
    Java垃圾回收
  • 原文地址:https://www.cnblogs.com/IdealSpring/p/11871208.html
Copyright © 2011-2022 走看看