【问题标题】:Seeming Discrepancy in Arrays.copyOfArrays.copyOf 中的看似差异
【发布时间】:2016-11-07 15:26:59
【问题描述】:

为什么这个问题不是可能与How Arrays.asList(int[]) can return List<int[]>? 重复。 这个问题并没有真正回答我的特殊情况,因为我试图弄清楚我对 Arrays.copyOf 的使用是否存在差异。

CASE 1:假设是数组的深拷贝

    // Creating a integer array, populating its values
    int[] src = new int[2]; 
    src[0] = 2;
    src[1] = 3;
    // Create a copy of the array
    int [] dst= Arrays.copyOf(src,src.length);
    Assert.assertArrayEquals(src, dst);
    // Now change one element in the original
    dst[0] = 4;
    // Following line throws an exception, (which is expected) if the copy is a deep one
    Assert.assertArrayEquals(src, dst);

案例 2: 这就是奇怪的地方: 我试图用下面的方法(从书中逐字提取)是创建输入数组参数副本的不可变列表视图。这样,如果输入数组发生变化,返回列表的内容不会改变。

    @SafeVarargs
    public static <T> List<T> list(T... t) {
    return Collections.unmodifiableList(new ArrayList<>(Arrays.asList(Arrays.copyOf(t, t.length))));
}


 int[] arr2 = new int[2];   
    arr2[0] = 2;
    arr2[1] = 3;
    // Create an unmodifiable list
    List<int[]> list2 = list(arr2);

    list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));
    // Prints [2, 3] as expected        

    arr2[0] = 3;

    list2.stream().forEach(s -> System.out.println(Arrays.toString(s)));    
    // Prints [3, 3] which doesn't make sense to me... I would have thought it would print [2, 3] and not be affected by my changing the value of the element.

我看到的矛盾是,在一种情况下(案例 1), Arrays.copyOf 似乎是一个深拷贝,而在另一种情况下(案例 2),它似乎是一个浅拷贝。对原始数组的更改似乎已写入列表,即使我在创建不可修改列表时复制了数组。

有人能帮我解决这个差异吗?

【问题讨论】:

  • 这里有很多问题。您将 int[] 传递给 varargs 方法。它被包装成一个Object[],你将它传递给copyOf。因此,copyOf 会复制包含单个 int[]Object[]。带有单个int[]Object[] 然后被包装成带有asListList,只包含int[]。然后该列表中的元素(int[] 被复制到一个新的ArrayList 中。它一直是相同的int[] 对象。
  • 谢谢,Sotirios。如果我理解正确,正在复制的是 Object[](它包含 int[]),因此我实际上并没有制作我认为我正在传递给 list() 方法的 int[] 的副本。在第一种情况下,它是对 int[] 的直接操作,所以我看到的是对数组副本的更改。

标签: java arrays list


【解决方案1】:

首先,你的 list 方法执行了一个不必要的步骤,你不需要 copyOf 操作,所以这里是:

@SafeVarargs
public static <T> List<T> list(T... t) {
    return Collections.unmodifiableList(
        new ArrayList<>(Arrays.asList(t))
    );
}

ArrayList 构造函数已经复制了传入的列表,所以你在那里是安全的。

接下来,当您使用 int[] 调用 list() 方法时,该数组被认为是 int[] 类型的单个元素,因为您的 T... 的类型擦除是 Object... , int 是原始的。如果不更改参数类型或进行 instanceOf 检查并在方法内手动执行复制,则无法使您的方法在列表中进行深层复制。我想说最明智的做法可能是将 Arrays.copyOf() 调用移到方法之外:

List<int[]> list2 = list(Arrays.copyOf(arr2));

【讨论】:

  • 谢谢肖恩。这很有意义。我也尝试了您的替代建议以满足我自己的好奇心,并且这些建议奏效了。再次感谢。
猜你喜欢
  • 2017-06-21
  • 2021-08-16
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
相关资源
最近更新 更多