代码改变世界

JAVA Collection 源码分析(二)之SubList

2014-08-01 13:59  西风狂诗曲  阅读(481)  评论(0编辑  收藏  举报

  昨天我们分析了ArrayList的源码,我们可以看到,在其中还有一个类,名为SubList,其继承了AbstractList。

// AbstractList类型的引用,所有继承了AbstractList都可以传进来
 private final AbstractList<E> parent;
//       这个是其实就是parent的偏移量,从parent中的第几个元素开始的
        private final int parentOffset;
        private final int offset;
        int size;

        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;
        }
// 从上面我们可以看出,其实就是一个相对的过程,截取完了以后还是原来的List,只是这里面
// 用了一个很巧妙的方法,用了offset的这个偏移量,他就指向我们截取过后的list的首个元素,
// 从下面的方法我们也可以看出,真是巧妙的数据结构的设计
// 以下就是它实现的具体方法,主要是注意到,现在的index都是相对于offset以后的位置
public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

        public E get(int index) {
            rangeCheck(index);
            checkForComodification();
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

        protected void removeRange(int fromIndex, int toIndex) {
            checkForComodification();
            parent.removeRange(parentOffset + fromIndex,
                               parentOffset + toIndex);
            this.modCount = parent.modCount;
            this.size -= toIndex - fromIndex;
        }

        public boolean addAll(Collection<? extends E> c) {
            return addAll(this.size, c);
        }

        public boolean addAll(int index, Collection<? extends E> c) {
            rangeCheckForAdd(index);
            int cSize = c.size();
            if (cSize==0)
                return false;

            checkForComodification();
            parent.addAll(parentOffset + index, c);
            this.modCount = parent.modCount;
            this.size += cSize;
            return true;
        }

  在subLIst我们可以找到我们昨天分析的modCount的答案,为什么对数组每次操作都要进行modCount++的操作,我们可以找到checkForComodification()这个方法,其实就是在迭代中,校验expectedModCount 等不等于 ArrayList.this.modCount

因为每次对数组进行操作的时候,modCount都会进行++,所以如果不相等的,就会报错,并发所产生的错误。

  所以Sublist其实就是还是原来的List,只是它在内部进行了巧妙的封装变换,这就是它的最大魅力所在。