阿里《Java开发手册》上提过
[强制] ArrayList的sublist结果不可強转成ArrayList,否则会抛出
ClassCastException
异常,即java.util.RandomAccesSubList cannot be cast to java. util.ArrayList
.
说明: subList 返回的是ArrayList 的内部类SubList, 并不是ArrayList ,而是ArrayList的一个视图,対于SubList子列表的所有操作最终会反映到原列表上。
private static void subListTest(){
List<String> names = new ArrayList<String>() {{
add("one");
add("two");
add("three");
}};
ArrayList strings = (ArrayList) names.subList(0, 1);
System.out.println(strings.toString());
}
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList
我猜问题是有八九就是出现在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
是一个继承 AbstractList
的内部类,在 SubList 的构建函数中的将 List 中的部分属性直接赋予给自己
SubList 没有创建一个新的 List,而是直接引用了原来的 List(this.parent = parent)
,指定了元素的范围
所以 subList
方法不能直接转成 ArrayList
,他只是ArrayList
的内部类,没有其他的关系
因为是引用的关系,所以在这里也需要特别的注意,如果对原来的List进行修改,会对产生的 subList结果产生影响。
List<String> names = new ArrayList<String>() {{
add("one");
add("two");
add("three");
}};
List strings = names.subList(0, 1);
strings.add(0, "ongChange");
System.out.println(strings.toString());
System.out.println(names.toString());
[ongChange, one]
[ongChange, one, two, three]
对subList产生的List做出结构型修改,操作会反应到原来的List上,ongChange也添加到了names中
如果修改原来的List则会抛出异常ConcurrentModificationException
List<String> names = new ArrayList<String>() {{
add("one");
add("two");
add("three");
}};
List strings = names.subList(0, 1);
names.add("four");
System.out.println(strings.toString());
System.out.println(names.toString());
Exception in thread "main" java.util.ConcurrentModificationException
原因:
subList的时候记录this.modCount
为3
原来的List插入了一个新元素,导致this.modCount
不第一次保存的不一致则抛出异常
解决方案:在操作SubList的时候,new一个新的ArrayList来接收创建subList结果的拷贝
List strings = new ArrayList(names.subList(0, 1));