IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> ArrayList源码解读(五) -> 正文阅读

[大数据]ArrayList源码解读(五)

一、subList(int fromIndex, int toIndex)

//返回此列表中指定的fromIndex (包含)和toIndex (不包含)之间的部分的视图
public List<E> subList(int fromIndex, int toIndex) {
		//判断参数的合法性
        subListRangeCheck(fromIndex, toIndex, size);
        //返回一个subList实例
        return new SubList(this, 0, fromIndex, toIndex);
}

//判断参数的合法性
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
        if (fromIndex < 0)
            throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
        if (toIndex > size)
            throw new IndexOutOfBoundsException("toIndex = " + toIndex);
        if (fromIndex > toIndex)
            throw new IllegalArgumentException("fromIndex(" + fromIndex +
                                               ") > toIndex(" + toIndex + ")");
 }
/*
     * SubList返回的视图是由父类集合支持的,因此是非结构化的
     * 所以,对SubList子集合进行操作,也会修改父类的集合。
     * SubList类中,每个public方法(除了subList()方法)都调用checkForComodification()
     * 用于判断父类集合是否被修改
     * 所以,如果直接使用父类方法修改集合,则SubList子类的遍历、增加、删除等操作都会抛出异常
     *
     * SubList 内部类,继承了 AbstractList 类,并实现了 RandomAccess 接口,支持随机读取
     */
private class SubList extends AbstractList<E> implements RandomAccess {
		// 父类的引用	
        private final AbstractList<E> parent;
        //父类集合中的位置,如果使用SubList中的subList方法,
        //则此时父类为SubList类,不是ArrayList
        private final int parentOffset;
        // 子类List在父类 ArrayList 中的下标位置
        private final int offset;
        // 视图集合的size
        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;
        }

        public E set(int index, E e) {
        	//传入参数索引合法性的检查
            rangeCheck(index);
            // 这个方法就是用来检验modCount从而触发fail-fast机制,
        	// 但是set这里modCount不会发生变化,所以不会触发fial-fast机制
            checkForComodification();
            // 从外部类(源列表)获取值
            E oldValue = ArrayList.this.elementData(offset + index);
            // 将外部类(源列表)的值替换成新的值,ArrayList的值是存在elementData的数组中的。
            // 调用父类方法替换元素,所以本质上还是在父类集合中替换元素
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }
        //从上面代码看出,修改subList的值其实是在修改源列表的值的,
        //所以源列表值发生变化是必然的。
        //代码中调用的是list.add而不是subList.add
        //也就是说我们没有再对SubList进行操作,SubList中的modCount也没有发生改变,
        //所有 ArrayList.this.modCount != this.modCount 成立,导致抛出了ConcurrentModificationException异常。
        //这里不仅打印会抛出异常,只要对subList进行操作都会抛出,因为SubList的方法都进行了checkForComodificatio,检查这两个modCount。


        public E get(int index) {
        	//传入参数索引合法性的检查
            rangeCheck(index);
            // 这个方法就是用来检验modCount从而触发fail-fast机制,
        	// 但是set这里modCount不会发生变化,所以不会触发fial-fast机制
            checkForComodification();
             // 从外部类(源列表)获取值
            return ArrayList.this.elementData(offset + index);
        }

        public int size() {
        	//检查modCount是否发生变化
            checkForComodification();
            return this.size;
        }

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            // 使用父类方法添加元素,下标位置为parentOffset + index, 在父类集合添加元素。
            parent.add(parentOffset + index, e);
            // 父类add()方法修改了modCount的值,更新subList的modCount值
            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 中迭代器使用ListIterator()
        public Iterator<E> iterator() {
            return listIterator();
        }

        public ListIterator<E> listIterator(final int index) {
            checkForComodification();
            rangeCheckForAdd(index);
            final int offset = this.offset;

            return new ListIterator<E>() {
                int cursor = index;
                int lastRet = -1;
                int expectedModCount = ArrayList.this.modCount;

                public boolean hasNext() {
                    return cursor != SubList.this.size;
                }

                @SuppressWarnings("unchecked")
                public E next() {
                    checkForComodification();
                    int i = cursor;
                    if (i >= SubList.this.size)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i + 1;
                    return (E) elementData[offset + (lastRet = i)];
                }

                public boolean hasPrevious() {
                    return cursor != 0;
                }

                @SuppressWarnings("unchecked")
                public E previous() {
                    checkForComodification();
                    int i = cursor - 1;
                    if (i < 0)
                        throw new NoSuchElementException();
                    Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length)
                        throw new ConcurrentModificationException();
                    cursor = i;
                    return (E) elementData[offset + (lastRet = i)];
                }

                @SuppressWarnings("unchecked")
                public void forEachRemaining(Consumer<? super E> consumer) {
                    Objects.requireNonNull(consumer);
                    final int size = SubList.this.size;
                    int i = cursor;
                    if (i >= size) {
                        return;
                    }
                    final Object[] elementData = ArrayList.this.elementData;
                    if (offset + i >= elementData.length) {
                        throw new ConcurrentModificationException();
                    }
                    while (i != size && modCount == expectedModCount) {
                        consumer.accept((E) elementData[offset + (i++)]);
                    }
                    // update once at end of iteration to reduce heap write traffic
                    lastRet = cursor = i;
                    checkForComodification();
                }

                public int nextIndex() {
                    return cursor;
                }

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

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

                    try {
                        SubList.this.remove(lastRet);
                        cursor = lastRet;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

                public void set(E e) {
                    if (lastRet < 0)
                        throw new IllegalStateException();
                    checkForComodification();

                    try {
                        ArrayList.this.set(offset + lastRet, e);
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }

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

                    try {
                        int i = cursor;
                        SubList.this.add(i, e);
                        cursor = i + 1;
                        lastRet = -1;
                        expectedModCount = ArrayList.this.modCount;
                    } catch (IndexOutOfBoundsException ex) {
                        throw new ConcurrentModificationException();
                    }
                }
				//检查是否有多线程修改集合
                final void checkForComodification() {
                    if (expectedModCount != ArrayList.this.modCount)
                        throw new ConcurrentModificationException();
                }
            };
        }
		// 内部方法
        public List<E> subList(int fromIndex, int toIndex) {
            subListRangeCheck(fromIndex, toIndex, size);
            return new SubList(this, offset, fromIndex, toIndex);
        }
		// 下标越界检查
        private void rangeCheck(int index) {
            if (index < 0 || index >= this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
		// 下标越界检查,仅add()方法和addAll()方法使用
        private void rangeCheckForAdd(int index) {
            if (index < 0 || index > this.size)
                throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        }
		// 下标越界异常信息
        private String outOfBoundsMsg(int index) {
            return "Index: "+index+", Size: "+this.size;
        }
		// 是否有多线程修改集合
        private void checkForComodification() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
        }

        public Spliterator<E> spliterator() {
            checkForComodification();
            return new ArrayListSpliterator<E>(ArrayList.this, offset,
                                               offset + this.size, this.modCount);
        }
    }

注意事项:

①subList方法传入的参数是左闭右开的,也就是[formIndex,toIndex)的形式。所以如果传来两个相同的index进去会返回一个空的列表。

②subList方法返回的只是一个视图,是一个对源列表的映射。这意味着如果对subList返回的列表进行编辑操作,源列表也会收到影响。

③对subList方法返回的列表进行添加、删除元素会抛出异常。

④如果只对subList方法返回的列表:subList进行增删元素的操作,并不会抛出异常,但是同样会影响源列表,因为subList的所有操作都是在操作源列表。

二、spliterator()

@Override
    public Spliterator<E> spliterator() {
        return new ArrayListSpliterator<>(this, 0, -1, 0);
    }
    
     static final class ArrayListSpliterator<E> implements Spliterator<E> {
     	// 存放ArrayList对象
     	private final ArrayList<E> list;
     	// 起始位置(包含)
        private int index; // current index, modified on advance/split
        // 结束位置(不包含)
        private int fence; // -1 until used; then one past last index
        // 存放list的modCount
        private int expectedModCount; // initialized when fence set

        /** Create new spliterator covering the given  range */
        ArrayListSpliterator(ArrayList<E> list, int origin, int fence,
                             int expectedModCount) {
            this.list = list; // OK if null unless traversed
            this.index = origin;
            this.fence = fence;
            this.expectedModCount = expectedModCount;
        }
		// 获取结束位置,用于初始化
        private int getFence() { // initialize fence to size on first use
            int hi; // (a specialized variant appears in method forEach)
            ArrayList<E> lst;
            // fence<0时(第一次初始化时,fence才会小于0)
            if ((hi = fence) < 0) {
                if ((lst = list) == null)
                	// list为null时,fence=0
                    hi = fence = 0;
                else {
                	// list不为null时,fence=list的长度
                    expectedModCount = lst.modCount;
                    hi = fence = lst.size;
                }
            }
            return hi;
        }
		// 分割list,返回一个新分割出的spliterator实例
        public ArrayListSpliterator<E> trySplit() {
        	// hi为结束位置,lo为起始位置,mid为中间值
            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
            // 当lo>=mid,表示不能在分割,返回null
            // 当lo<mid,以mid分割,同时更新index。返回的是list前半部分,当前对象保留后半部分
            return (lo >= mid) ? null : // divide range in half unless too small
                new ArrayListSpliterator<E>(list, lo, index = mid,
                                            expectedModCount);
        }
		// 返回true 时,只表示可能还有元素未处理
        // 返回false 时,没有剩余元素处理了。。
        public boolean tryAdvance(Consumer<? super E> action) {
            if (action == null)
                throw new NullPointerException();
             // hi是结束位置,i是起始位置
            int hi = getFence(), i = index;
            if (i < hi) {
            	// 处理i位置元素,index+1
                index = i + 1;
                @SuppressWarnings("unchecked") E e = (E)list.elementData[i];
                // 调用action.accept处理元素
                action.accept(e);
                if (list.modCount != expectedModCount)
                	// 遍历时,多线程操作结构发生变更,抛出异常
                    throw new ConcurrentModificationException();
                return true;
            }
            return false;
        }
		// 顺序处理元素
        public void forEachRemaining(Consumer<? super E> action) {
            int i, hi, mc; // hoist accesses and checks from loop
            ArrayList<E> lst; Object[] a;
            if (action == null)
                throw new NullPointerException();
            if ((lst = list) != null && (a = lst.elementData) != null) {
            	// 当fence<0时,进行初始化操作
                if ((hi = fence) < 0) {
                    mc = lst.modCount;
                    hi = lst.size;
                }
                else
                    mc = expectedModCount;
                if ((i = index) >= 0 && (index = hi) <= a.length) {
                    for (; i < hi; ++i) {
                        @SuppressWarnings("unchecked") E e = (E) a[i];
                        // 调用action.accept处理元素
                        action.accept(e);
                    }
                    if (lst.modCount == mc)
                        return;
                }
            }
            throw new ConcurrentModificationException();
        }
		 // 估算大小
        public long estimateSize() {
            return (long) (getFence() - index);
        }

        public int characteristics() {
        	// 返回特征值
            return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
        }
    }

总结

ArrayListSpliterator:ArrayList可分割的迭代器,基于二分法的可分割迭代器,是为了并行遍历元素而设计的一种迭代器,jdk1.8 中的集合框架中的数据结构都默认实现了 spliterator。

Itr:实现Iterator接口的迭代器,为ArrayList进行优化。

ListItr:实现ListIterator接口的迭代器,为ArrayList进行优化。

SubList:实现了AbstractList和RandomAccess接口的子列表。(为了处理局部列表而设计的子列表类)

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-12-11 15:47:32  更:2021-12-11 15:50:12 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:41:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码