Java开发手册中为什么要求谨慎使用ArrayList中的sublist方法

场景

Java开发手册中对于ArrayList的subList的要求如下:

【强制】ArrayList 的 subList 结果不可强转成 ArrayList,否则会抛出 ClassCastException 异常:

java.util.RandomAccessSubList cannot be cast to java.util.ArrayList。

说明:subList()返回的是 ArrayList 的内部类 SubList,并不是 ArrayList 本身,

而是 ArrayList 的一个视图,对于 SubList 的所有操作最终会反映到原列表上。

 

注:

博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

subList 是 List 接口中定义的一个方法,该方法主要用于返回一个集合中的一段、可以理解为截取一个集合中的部分元素,

他的返回值也是一个 List。

使用示例:

        List<String> names = new ArrayList<String>(){
   
   {
            add("ba");
            add("dao");
            add("de");
            add("cheng");
            add("xv");
            add("yuan");
        }};

        List<String> subList = names.subList(0, 2);
        System.out.println(subList);

但是如果将subList的返回值强转为ArrayList则会抛出异常java.util.ArrayList$SubList cannot be cast to java.util.ArrayList

ArrayList<String> subList1 = (ArrayList<String>) names.subList(0, 2);

查看sublist的源码可知

Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.

 (If fromIndex and toIndex are equal, the returned list is empty.)

 The returned list is backed by this list, so non-structural changes in the returned list are reflected in this list,

and vice-versa. The returned list supports all of the optional list operations supported by this list.

翻译过来就是

返回此列表中位于指定的fromIndex(包含)和toIndex(排除)之间的部分的视图。

(如果fromIndex和toIndex相等,则返回的列表为空。)

返回的列表由该列表支持,因此返回列表中的非结构性更改会反映在此列表中,

 反之亦然。返回的列表支持此列表支持的所有可选列表操作。

 

这个方法返回了一个 SubList,这个类是 ArrayList 中的一个内部类。

            public List<E> subList(int fromIndex, int toIndex) {
                subListRangeCheck(fromIndex, toIndex, size);
                return new SubList(this, 0, fromIndex, toIndex);
            }

SubList 这个类中单独定义了 set、get、size、add、remove 等方法。

当我们调用subList方法的时候,会通过调用SubList的构造函数创建一个SubList,

那么看下这个构造函数做了哪些事情。

                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 以及该 List 中的部分属性直接赋值给自己的一些属性了。

也就是说,SubList 并没有重新创建一个 List,而是直接引用了原有的 List(返回了父类的视图),

只是指定了一下他要使用的元素的范围而已(从 fromIndex(包含),到 toIndex(不包含))。

所以验证下调用sublist的set方法

        subList.set(0,"666");
        System.out.println(names);//[666, dao, de, cheng, xv, yuan]

使用sublist的set等方法修改元素值时,发现原来的那个list的元素值也发生了改变,同理对sublist进行add操作时也是如此

如何创建新的sublist?

如果需要对sublist做出修改,又不想动原list,那么可以创建出sublist的一个拷贝。

猜你喜欢

转载自blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/131053593
今日推荐