removeRange(int, int);这个方法AbstractList并没有暴露出来,我们应该如何得到一个截短的list?
1 如何得到一个list某个范围的子集sublist
首先想到sublist(int, int)方法
注意此方法参数左闭右开。
测试如下
1.1 修改sublist会影响原来的list
-
LinkedList<String> ll =
new LinkedList<>();
-
ll.
add(
"a");
-
ll.
add(
"b");
-
ll.
add(
"c");
-
List<String> l2 = ll.subList(
1,
2);
-
l2.
add(
"new");
-
System.
out.println(ll);
-
System.
out.println(l2);
[a, b, new, c]
[b, new]
可见sublist是快照,sulist插入会影响原list
1.2 修改原list,则sublist的所有操作会报错
-
LinkedList<String> ll =
new LinkedList<>();
-
ll.
add(
"a");
-
ll.
add(
"b");
-
ll.
add(
"c");
-
List<String> l2 = ll.subList(
1,
2);
//[)
-
ll.
add(
"d");
-
System.
out.println(ll);
-
System.
out.println(l2);
Exception in thread “main” java.util.ConcurrentModificationException
at java.util.SubList.checkForComodification(AbstractList.java:769)
可见如果更改了原来的list,sublist的任何操作都会报错,包括get() size(),listIterator()等所有调用checkForComodification()的地方。
2 如何正确的截断一个List?
subList()返回的是List!是Sublist,而不是原来的类型。
2.1在java.util.AbstractList.subList(int fromIndex, int toIndex)的定义,返回的是java.util.SubList.SubLis:
-
public List<E> subList(int fromIndex, int toIndex) {
-
return (
this
instanceof RandomAccess ?
-
new RandomAccessSubList<>(
this, fromIndex, toIndex) :
-
new SubList<>(
this, fromIndex, toIndex));
-
}
-
声明:
-
class SubList<E> extends AbstractList<E>{}
2.2 LinkedList并没有覆盖这个方法.ArryList自己覆盖了这个方法,返回的是java.util.ArrayList.SubList:
-
public List<E> subList(int fromIndex, int toIndex) {
-
subListRangeCheck(fromIndex, toIndex, size);
-
return
new SubList(
this,
0, fromIndex, toIndex);
-
}
-
声明:
-
private
class SubList extends AbstractList<E> implements RandomAccess {}
看来ArryList处处体现出RandomAccess接口的特性——支持随机访问。
2.3 我们看一下java.util.AbstractList.clear()方法,这正是我们需要的,Sublist的clear就是这个方法
-
public void clear() {
-
removeRange(
0, size());
-
}
2.3.1 ArrayList的覆盖
-
public void clear() {
-
modCount++;
-
-
// clear to let GC do its work
-
for (
int i =
0; i < size; i++)
-
elementData[i] =
null;
-
-
size =
0;
-
}
2.3.2 LinkedList的覆盖
-
public void clear() {
-
for (Node<E> x = first; x !=
null; ) {
-
Node<E>
next = x.
next;
-
x.item =
null;
-
x.
next =
null;
-
x.prev =
null;
-
x =
next;
-
}
-
first = last =
null;
-
size =
0;
-
modCount++;
-
}
3 根据1和2
截短一个List的正确姿势:
list.subList(from, to).clear();
总之:
subList是返回一个镜像而不是新示例 用了 得保证原来的list不能更改。
之前的抛异常是因为更改了原来的list而要使用sublist的时候必然报异常。
clear的这个跟这个问题说的是如何获得一个list的某一段顺便释放其他节点。
这个操作后原来的list会截取出来 类型不变。
而subList实际上返回的是java.util.Sublist或者java.util.ArrayList.Sublist。