一、场景
我们知道String类有分割字符串的作用(subString函数),当然在List集合里面也提供了分割集合的作用(subList函数)。
但List的这个分割方法有坑啊,如下面代码:
1、正常使用:
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
List<String> list = arrayList.subList(0, 2);
System.out.println(list);
输出:
2、带坑的使用:
List<String> arrayList = new ArrayList<String>();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
List<String> arrayList_subList = arrayList.subList(0, 2);
arrayList.remove(0);
arrayList.add("d");
System.out.println(arrayList_subList.size());
输出:
最后一行报错。按正常的代码逻辑思维,arrayList_subList新建了一个新对象List,保存分割的数据,后续父List的改变应该不影响子List的,但是不是的。
二、原因分析:
看这个函数的官方文档:
/** * Returns a view of the portion of this list between the specified * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive. (If * {@code fromIndex} and {@code 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.<p> * * This method eliminates the need for explicit range operations (of * the sort that commonly exist for arrays). Any operation that expects * a list can be used as a range operation by passing a subList view * instead of a whole list. For example, the following idiom * removes a range of elements from a list: * <pre>{@code * list.subList(from, to).clear(); * }</pre> * Similar idioms may be constructed for {@code indexOf} and * {@code lastIndexOf}, and all of the algorithms in the * {@code Collections} class can be applied to a subList.<p> * * The semantics of the list returned by this method become undefined if * the backing list (i.e., this list) is <i>structurally modified</i> in * any way other than via the returned list. (Structural modifications are * those that change the size of this list, or otherwise perturb it in such * a fashion that iterations in progress may yield incorrect results.) * * @param fromIndex low endpoint (inclusive) of the subList * @param toIndex high endpoint (exclusive) of the subList * @return a view of the specified range within this list * @throws IndexOutOfBoundsException for an illegal endpoint index value * ({@code fromIndex < 0 || toIndex > size || * fromIndex > toIndex}) */
根据注释得知:
1,该方法返回的是父list的一个视图,从fromIndex(包含),到toIndex(不包含)。fromIndex=toIndex 表示子list为空
2,父子list做的非结构性修改(non-structural changes)都会影响到彼此:所谓的“非结构性修改”,是指不涉及到list的大小改变的修改。相反,结构性修改,指改变了list大小的修改。
3,对于结构性修改,子list的所有操作都会反映到父list上。但父list的修改将会导致返回的子list失效。
4,tips:如何删除list中的某段数据:
list.subList(from, to).clear();
下面一段代码验证第三点:
List<String> list = new ArrayList<String>();
list.add("a");
// 使用构造器创建一个包含list的列表list1
List<String> list1 = new ArrayList<String>(list);
// 使用subList生成与list相同的列表list2
List<String> list2 = list.subList(0, list.size());
list2.add("b");
System.out.println(list.equals(list1));
System.out.println(list.equals(list2));
输出:
三、总结
多看源码。