asList和subList的“坑”

本文深入探讨了Java中Arrays.asList方法如何将数组转换为List,以及由此产生的List特性,强调了其不可修改的结构。同时,详细解析了List.subList方法,说明它返回的是原列表的视图,对子列表的修改会影响到原列表,并解释了在修改过程中可能出现的并发修改异常。此外,还介绍了modCount在确保列表结构一致性中的作用。
摘要由CSDN通过智能技术生成

asList

asList是Arrays的一个可以将数组转换为List的方法,具体用法如下:

String[] arr = new String[]{"a","b","c"};
List<String> list = Arrays.asList(arr);

先说结论:

  1. 原数组和asList得到的list使用的是同一份元素数组的内存空间,因此,无论是在原数组和list修改某元素的值,都会互相影响。
  2. 得到的ArrayList是Arrays里的一个内部类,调用结构性修改的方法(add,remove)会抛出异常。

Arrays.asList返回的是一个“ArrayList”,但并非我们熟悉的ArrayList,该ArrayList是Arrays里的一个内部类。
在这里插入图片描述
该ArrayList同样继承了AbstractList,但只重写(实现)了部分方法,如size,get,set等方法,对于对结构修改的方法如add,remove并没有重写,而是直接继承了原抽象类AbstractList的方法。
在这里插入图片描述
因此如果通过Arrays.asList拿到的list直接调用这些方法,会直接抛出UnsupportedOperationException异常。

另外还有一个值得注意的点是,原数组和新得到的list使用的是同一份元素数组的内存空间,因此,无论是在原数组和list修改某元素的值,都会互相影响。

subList

subList() 方法用于截取并返回动态数组中的一部分,类似substring方法。用法如下:

		// 创建一个动态数组
        ArrayList<String> list= new ArrayList<>();
        sites.add("a");
        sites.add("b");
        sites.add("c");
        List<String> subList = list.subList(0, 2);//["a","b"]

先说结论:

  1. subList是list的一个视图,两个list同一份元素数组,两个list各自调用非结构性修改如set方法均会影响对方。
  2. subList的结构性修改如add,remove会直接修改双方的结构,但不会有任何问题。
  3. list的结构性修改如add,remove会造成subList的不可用:get,add,size()等方法调用后均会报错。

subList方法,返回的并不是真正意义上返回和原来list同数据结构的类,ArrayList.subList返回的是一个名为SubList的ArrayList的一个内部类,LinkedList.subList返回的是AbstractList文件里的名为SubList的类,下面为ArrayList里的SubList
在这里插入图片描述
下面来分析下第3点的报错:
这个SubList类有个很重要的特点是,在调用几乎所以方法前都会去调用一个校验方法:
在这里插入图片描述
在这里插入图片描述
就是checkForComodification这个方法,这个方法很简单,就是检查一下外部的ArrayList类的modCount 和 自己的modCount是否一致,不一致直接抛出ConcurrentModificationException异常。
modCount 是什么?它是一个记录着ArrayList结构变化次数的字段,当ArrayList结构修改时会自增。
调用subList方法返回的SubList类会复制外部的ArrayList类的modCount,因此ArrayList进行add,remove结构性变化时就会导致modCount 变化,从而和subList最初记录的modCount 不一致而抛出异常。

而subList自己的结构性修改则是会重置modCount和ArrayList保持一致,所以它的修改不会造成任何异常发生。

父集合的modCount实际上可以理解为记录了自己结构的版本号,子集合任何的操作都要保证自己最初拿到的那份父集合的结构和当前的是一致的,防止结构混乱。

这和在迭代遍历中执行修改结构的操作异常发生类似,迭代器生成的时候也会copy一份modCount命名为expectedModCount,进行迭代操作时会校验当前的List的modCount和expectedModCount是否一致,否则抛出ConcurrentModificationException异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值