ArrayList的removeRange方法如何工作?

时间:2019-06-21 16:21:42

标签: java arraylist

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]


  }     
}

1 个答案:

答案 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}},其行为应如下:

  

从指定的源数组(从指定位置开始)复制数组到目标数组的指定位置。 [...]

     

如果srcdest参数引用相同的数组对象,则执行复制,就好像位置srcPossrcPos+length-1的组件首先复制到一个具有length个组件的临时数组,然后将临时数组的内容复制到目标数组的destPosdestPos+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)