ArrayList的removeRange很奇怪。检查下面的示例代码,我反向输入。我认为该列表已被反向删除。
Ex:3到1表示删除了三个元素(第3、2和1st)。
但是,输出完全让我感到困惑。想知道它是如何工作的?
在JavaDoc中,我找到了以下语句。如果toIndex IndexOutOfBoundsException-如果fromIndex或toIndex超出范围
(fromIndex <0 || fromIndex> = size()|| toIndex> size()|| toIndex <
fromIndex )
import java.util.*;
public class TestRemoveRange extends ArrayList {
public static void main(String arg[]){
TestRemoveRange list = new TestRemoveRange();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
System.out.println("before remove : " + list);
list.removeRange(3, 1);
System.out.println("after remove (3, 1) : " + list); //[a, b, c, b, c, d, e]
}
}
答案 0 :(得分:4)
查看实际的源代码可能有助于阐明您的问题:
在 Java 8 中,ArrayList.removeRange()
如下所示:
protected void removeRange(int fromIndex, int toIndex) {
modCount++;
int numMoved = size - toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// clear to let GC do its work
int newSize = size - (toIndex-fromIndex);
for (int i = newSize; i < size; i++) {
elementData[i] = null;
}
size = newSize;
}
在 Java 9 中,ArrayList.removeRange()
更改为:
protected void removeRange(int fromIndex, int toIndex) {
if (fromIndex > toIndex) {
throw new IndexOutOfBoundsException(
outOfBoundsMsg(fromIndex, toIndex));
}
modCount++;
shiftTailOverGap(elementData, fromIndex, toIndex);
}
private void shiftTailOverGap(Object[] es, int lo, int hi) {
System.arraycopy(es, hi, es, lo, size - hi);
for (int to = size, i = (size -= hi - lo); i < to; i++)
es[i] = null;
}
如您在上面的摘录中所见,两种实现都使用System.arraycopy()
删除列表中的项目。但是只有从Java 9开始,如果IndexOutOfBoundsException
,才有抛出fromIndex > toIndex
的检查。
由于System.arraycopy()
is implemented native the source code在不同平台上可能有所不同。根据{{3}},其行为应如下:
从指定的源数组(从指定位置开始)复制数组到目标数组的指定位置。 [...]
如果
src
和dest
参数引用相同的数组对象,则执行复制,就好像位置srcPos
至srcPos+length-1
的组件首先复制到一个具有length
个组件的临时数组,然后将临时数组的内容复制到目标数组的destPos
至destPos+length-1
的位置。
对于IndexOutOfBoundException
,它说:
如果以下任何一项为真,则会抛出
IndexOutOfBoundsException
并且目标不会被修改:
srcPos
参数为负。destPos
参数为负。length
参数为负。srcPos+length
大于源数组长度src.length
。destPos+length
大于目标数组的长度dest.length
。
因此,如果您使用 Java 8 或更低版本运行示例,则可能会得到以下结果:
before remove : [a, b, c, d, e]
after remove (3, 1) : [a, b, c, b, c, d, e]
如果您使用 Java 9 或更高版本运行示例,则会出现以下异常:
before remove : [a, b, c, d, e]
Exception in thread "main" java.lang.IndexOutOfBoundsException: From Index: 3 > To Index: 1
at java.base/java.util.ArrayList.removeRange(ArrayList.java:769)
at TestRemoveRange.main(TestRemoveRange.java:16)