方法
subList(int fromIndex, int toIndex)
可以看一下subList源码片段
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList<>(this, fromIndex, toIndex);
}
private static class SubList<E> extends AbstractList<E> implements RandomAccess{
...
}
可以看一下继承关系。
可以得到以下几个关键信息:
subList
返回的是一个SubList
类型的对象- 对原
list
和新list
做非结构性修改都会影响到彼此 - 对原
list
做非结构性修改,会报错
验证:对原list和新list做非结构性修改都会影响到彼此
public static void main(String[] args) {
ArrayList old_list = new ArrayList();
old_list.add("1"); old_list.add("1"); old_list.add("1"); old_list.add("1"); old_list.add("1");
List new_list = old_list.subList(1, 3);
System.out.println("原list = " + old_list.toString() + "新list = " + new_list.toString());
old_list.set(2, "hh"); // 对原list进行非结构性修改
System.out.println("原list = " + old_list.toString() + "新list = " + new_list.toString());
new_list.set(0, "xx");// 对新list进行非结构性修改
System.out.println("原list = " + old_list.toString() + "新list = " + new_list.toString());
}
输出:
原list = [1, 1, 1, 1, 1]新list = [1, 1]
原list = [1, 1, hh, 1, 1]新list = [1, hh]
原list = [1, xx, hh, 1, 1]新list = [xx, hh]
验证:对原list
做结构性修改,会报错
public static void main(String[] args) {
ArrayList old_list = new ArrayList();
old_list.add("1"); old_list.add("1"); old_list.add("1"); old_list.add("1"); old_list.add("1");
List new_list = old_list.subList(1, 3);
System.out.println("原list = " + old_list.toString() + "新list = " + new_list.toString());
old_list.add(5);
System.out.println("原list = " + old_list.toString() + "新list = " + new_list.toString());
}
输出:
原list = [1, 1, 1, 1, 1]新list = [1, 1]
Exception in thread "main" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1415)
at java.base/java.util.ArrayList$SubList.listIterator(ArrayList.java:1284)
at java.base/java.util.AbstractList.listIterator(AbstractList.java:311)
at java.base/java.util.ArrayList$SubList.iterator(ArrayList.java:1280)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:449)
at com.example.sprint_test01.TestArrayList.main(TestArrayList.java:22)
为什么呢?看一下源码,在jdk注释里有这么一段话:
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.
意思就是说,subList方法返回的是一个视图,可以理解为一个映射窗口,fromIndex
和toIndex
理解为窗口的边界,我们就可以看
到这个边界内的元素,当内部元素改变的时候,我们看到的也就变了,理解为一个引用。
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList<>(this, fromIndex, toIndex);
}
private static class SubList<E> extends AbstractList<E> implements RandomAccess {
private final ArrayList<E> root;
private final SubList<E> parent;
private final int offset;
private int size;
/**
* Constructs a sublist of an arbitrary ArrayList.
*/
public SubList(ArrayList<E> root, int fromIndex, int toIndex) {
this.root = root;
this.parent = null;
this.offset = fromIndex;
this.size = toIndex - fromIndex;
this.modCount = root.modCount;
}
/**
* Constructs a sublist of another SubList.
*/
private SubList(SubList<E> parent, int fromIndex, int toIndex) {
this.root = parent.root;
this.parent = parent;
this.offset = parent.offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = parent.modCount;
}
可以看到,调用subList
方法的时候,我们用的其实就是引用的原有的list
,并规定了边界。
同时可以看到为什么subList
得到的集合不能转换为ArrayList
,因为SubList
只是ArrayList
的内部类,与其并没有继承关系。