Arrays.copyOfRange(byte [],int,int)背后的逻辑是什么奇怪的行为?

时间:2017-09-08 07:30:05

标签: java arrays standard-library

任何人都可以向我解释 Arrays.copyOfRange(byte[], int, int))奇怪行为背后的逻辑吗?我可以用简单的例子来说明我的意思:

byte[] bytes = new byte[] {1, 1, 1};
Arrays.copyOfRange(bytes, 3, 4); // Returns single element (0) array
Arrays.copyOfRange(bytes, 4, 5); // Throws ArrayIndexOutOfBoundsException

在这两种情况下,我都会在数组边界之外复制范围 (即start >= array.length),因此错误的条件对我来说至少是奇怪的(如果是from < 0或{{ 1}})。我认为应该是:from > original.lengthfrom < 0。也许我错过了什么?

4 个答案:

答案 0 :(得分:4)

The JavaDoc指出了关于它所期望的论点的三点:

一:

  

[来自] 必须介于 original.length 之间,包括

二:

  

[ to ] 必须大于或等于来自

三:

  

[ to ]可能大于 original.length

对于Arrays.copyOfRange(bytes, 3, 4)的情况,一,二,三是真的,这意味着它们是有效的。

对于Arrays.copyOfRange(bytes, 4, 5)的情况,只有两个和三个为真,这意味着它们无效。

预期的行为?是。

不直观的行为?有点。

如果您的问题是秘密地“为什么是这样设计的?”除了代码作者,没有人可以告诉你答案。

答案 1 :(得分:0)

看看copyOfRange的工作原理:

public static <T,U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType) {
    int newLength = to - from;
    if (newLength < 0)
        throw new IllegalArgumentException(from + " > " + to);
    @SuppressWarnings("unchecked")
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));
    return copy;
}

最重要的部分是:

System.arraycopy(original, from, copy, 0,
                     Math.min(original.length - from, newLength));

所以当你调用Arrays.copyOfRange(bytes,3,4)时; System.arraycopy的最后一个参数“length - 要复制的数组元素的数量”是0. arraycopy的调用看起来像System.arraycopy(original,from,copy,0,0);

答案 2 :(得分:0)

查看Arrays.copyOfRange(byte[] original, int from, int to)

的来源
  public static byte[] copyOfRange(byte[] original, int from, int to) {
1     int newLength = to - from;
2     if (newLength < 0)
3         throw new IllegalArgumentException(from + " > " + to);
4     byte[] copy = new byte[newLength];
5     System.arraycopy(original, from, copy, 0,
6                      Math.min(original.length - from, newLength));
7     return copy;
  }
  • 在第1行,使用1
  • 计算目标数组的长度
  • 在第4行,新数组的大小为1,所有元素均为0
  • 在第6行,要复制的元素的长度计算为零,因为

    // Math.min(original.length - from, newLength));
    Math.min(3 - 3, 1)); --> returns zero
    
  • 在第5行,System.arraycopy根本不会将任何内容复制到数组copy

如果frombytes.length + 1,则length为负(bytes.length - from)。

要演示的小代码

public class ArrayCopy {

    public static void main(String[] args) {
        byte[] bytes = new byte[]{11, 12, 13};
        int from = 3;
        int to = 4;
        copyOfRange(bytes, from, to);

        from = 2;
        to = 3;
        copyOfRange(bytes, from, to);

        from = 4;
        to = 5;
        copyOfRange(bytes, from, to);
    }

    static void copyOfRange(byte[] bytes, int from, int to) {
        System.out.printf("%ncopyOfRange(bytes: %s  from: %d  to: %d)%n",
                Arrays.toString(bytes),
                from,
                to
                );

        // line 1
        int newLength = to - from;
        System.out.println("int newLength = " + newLength);

        // line 2
        if (newLength < 0) {
            throw new IllegalArgumentException(from + " > " + to);
        }

        // line 4
        byte[] copy = new byte[newLength];

        // to show that in the suspicious case System.arrayCopy does nothing
        copy[0] = 42;
        System.out.println("byte[] copy   = " + Arrays.toString(copy));
        int length = bytes.length - from;
        System.out.println("int length    = " + length);
        int minLenght = Math.min(length, newLength);
        System.out.println("int minLenght = " + minLenght);

        // line 5
        System.arraycopy(bytes, from, copy, 0, minLenght);

        System.out.println("byte[] copy   = " + Arrays.toString(copy));
    }
}

输出

copyOfRange(bytes: [11, 12, 13]  from: 3  to: 4)
int newLength = 1
byte[] copy   = [42]
int length    = 0
int minLenght = 0
byte[] copy   = [42]

copyOfRange(bytes: [11, 12, 13]  from: 2  to: 3)
int newLength = 1
byte[] copy   = [42]
int length    = 1
int minLenght = 1
byte[] copy   = [13]

copyOfRange(bytes: [11, 12, 13]  from: 4  to: 5)
int newLength = 1
byte[] copy   = [42]
int length    = -1
int minLenght = -1
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException

答案 3 :(得分:0)

这意味着您可以使用此方法创建任意长度的新“空”数组,就像您在 Model MPG Cylinders Engine Disp Horsepower Weight Accelerate Year Origin 0 amc ambassador dpl 15.0 8 390 190 3850 8.5 70 American 1 amc gremlin 21.0 6 199 90 2648 15.0 70 American 2 amc hornet 18.0 6 199 97 2774 15.5 70 American 3 amc rebel sst 16.0 8 304 150 3433 12.0 70 American 4 buick estate wagon (sw) 14.0 8 455 225 3086 10.0 70 American 5 buick skylark 320 15.0 8 350 165 3693 11.5 70 American 8 volkswagen 1131 deluxe sedan 26.0 4 97 46 1835 20.5 70 European 12 volkswagen model 111 27.0 4 97 60 1834 19.0 71 European 情况中所描述的那样。

// Returns single element (0) array方法存在的主要目的是因为它“动态”创建新数组。当然,这个新阵列可能比源阵列更大。

该行为是documented功能。

  

范围的最终索引(to),必须大于或等于from,可能大于original.length ,在这种情况下   '\ u000'放置在索引较大的副本的所有元素中   大于或等于original.length - 来自。返回的长度   数组将来自 - 。

为什么这样实施?假设你要调用它:

Arrays.copyOfRange

它将创建数组[1,0,0,0],并且原始数组中不存在的所有元素将按当前类型的默认文字初始化。 如果您想指定byte[] bytes = new byte[] {1, 1, 1}; byte[] newBytes = Arrays.copyOfRange(bytes, 2, 6); // Returns array length 6 - 2 = 4 更大但不等于from(文档不鼓励),则在调用此bytes.length时会导致ArrayIndexOutOfBoundsException因为System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength));将小于original.length - from

技术上说如果你使用这样的指示:

0

假设您只想创建一个大小为int n = 4; Arrays.copyOfRange(bytes, bytes.length, bytes.length + n); 的新空数组。换句话说,您正在创建一个新数组并从源数组中复制任何内容。