数组8:解析《阿里巴巴开发手册》中ArrayList的subList的
Posted 纵横千里,捭阖四方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数组8:解析《阿里巴巴开发手册》中ArrayList的subList的相关的知识,希望对你有一定的参考价值。
在《阿里巴巴Java开发手册》泰山版中关于subList有这样的两个描述
这里是啥意思呢?我们来分析一下:
先来看下subList的简单使用:
List<String> bookList = new ArrayList<>();
bookList.add("面上头条快手阿里");
bookList.add("升职加薪");
bookList.add("当上CTO");
bookList.add("迎娶白富美");
bookList.add("走向人生巅峰");
List<String> lqcBookList = bookList.subList(3, 5);
System.out.println(bookList);
System.out.println(lqcBookList);
运行结果如下图所示:
[面上头条快手阿里, 升职加薪, 当上CTO, 迎娶白富美, 走向人生巅峰]
[迎娶白富美, 走向人生巅峰]
从运行结果可以看出,subList返回的是bookList中索引从fromIndex(包含)到toIndex(不包含)的元素集合。
使用起来很简单,也很好理解,不过呢,要注意,修改原始集合会影响到子集合,如果修改子集合,会影响到原始集合。
比如,我们修改下原集合bookList中某一元素的值(非结构性修改):
public static void testSubList() {
List<String> bookList = new ArrayList();
bookList.add("面上头条快手阿里");
bookList.add("升职加薪");
bookList.add("当上CTO");
bookList.add("迎娶白富美");
bookList.add("走向人生巅峰");
List<String> lBookList = bookList.subList(2, 5);
System.out.println("修改前:");
System.out.println("bookList:" + bookList);
System.out.println("lBookList:" + lBookList);
// 修改原集合的值
bookList.set(2, "CEO也行");
System.out.println("修改后:");
System.out.println("bookList:" + bookList);
System.out.println("lBookList:" + lBookList);
}
打印结果:
修改前:
bookList:[面上头条快手阿里, 升职加薪, 当上CTO, 迎娶白富美, 走向人生巅峰]
lBookList:[当上CTO, 迎娶白富美, 走向人生巅峰]
修改后:
bookList:[面上头条快手阿里, 升职加薪, CEO也行, 迎娶白富美, 走向人生巅峰]
lBookList:[CEO也行, 迎娶白富美, 走向人生巅峰]
可以看到,我们修改原始的bookList,结果子集合lBookList也被修改了,“当上CTO”被换成了“CEO也行”。
另外一条:“修改原集合的结构,会引起ConcurrentModificationException异常”又是怎么回事呢?
比如,我们往原集合bookList中添加一个元素(结构性修改):
public static void testSubList() {
List<String> bookList = new ArrayList();
bookList.add("面上头条快手阿里");
bookList.add("升职加薪");
bookList.add("当上CTO");
bookList.add("迎娶白富美");
bookList.add("走向人生巅峰");
List<String> lBookList = bookList.subList(2, 5);
System.out.println("修改前:");
System.out.println("bookList:" + bookList);
System.out.println("lBookList:" + lBookList);
//原始集合添加一项
bookList.add( "想想有点小激动");
System.out.println("修改后:");
System.out.println("bookList:" + bookList);
System.out.println("lBookList:" + lBookList);
}
我们可以看到在打印子list的时候抛异常了:
这里虽然原始list添加成功了,但是在执行打印子list的时候抛出了异常。
需要注意的是,以上异常并不是在添加元素时发生的,而是在添加元素后,遍历子集合时发生的。
那这是什么道理呢?还是看看源代码吧
首先,我们看下subList
方法的注释,了解下它的用途:
Returns a view of the portion of this list between the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
说人话就是:返回指定的fromIndex和toIndex之间的列表部分的视图。
然后,我们看下它的源码:
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
可以看到,它调用了SubList类的构造函数,该构造函数的源码如下所示:
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> 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;
}
····
}
可以看出,SubList类是ArrayList的内部类,该构造函数中也并没有重新创建一个新的ArrayList,只是直接使用了原始List的游标。也就是说两者其实指向了同一个堆内存空间,SubList只是为了方便操作增加了新的指示游标而已。因此修改其中一个就会影响到另一个。在业务中这是很危险的,可能导致未知的错误,所以不能这么做。
总结
ArrayList的subList方法,返回的是原集合的一个子集合(视图),非结构性修改任意一个集合的元素的值,都会彼此影响,结构性修改原集合时,会报ConcurrentModificationException
异常,结构性修改子集合时,会影响原集合,所以使用时要注意,避免程序错误或者异常。
以上是关于数组8:解析《阿里巴巴开发手册》中ArrayList的subList的的主要内容,如果未能解决你的问题,请参考以下文章