ArrayList的removeRange很奇怪。检查下面的示例代码,我反向输入。我认为该列表已被反向删除。
例如:3到1表示删除了三个元素(第3、2和1st)。
但是,输出完全让我感到困惑。好奇地知道,它是如何工作的?
在JavaDoc中,我找到了以下语句。如果toIndex
IndexOutOfBoundsException-如果fromIndex或toIndex超出范围
(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]
}
}
最佳答案
查看实际的源代码可能有助于阐明您的问题:
在 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在不同平台上可能有所不同。根据javadoc,它的行为应为:从指定的源数组(从指定位置开始)复制数组到目标数组的指定位置。 [...]
如果
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)