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,它的行为应为:

从指定的源数组(从指定位置开始)复制数组到目标数组的指定位置。 [...]
如果srcdest参数引用相同的数组对象,则执行复制,就好像首先将srcPossrcPos+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)
    

    10-07 18:48