java.lang.IndexOutOfBoundsException: 源数据长度超过了目标数组长度

80

以下是代码示例:

static void findSubsets (ArrayList<Integer> numbers, int amount, int index)
{
    ArrayList <Integer> numbersCopy = new ArrayList<Integer>(numbers.size());
    Collections.copy(numbersCopy, numbers);
}

我遇到了这个错误:

Exception in thread "main" java.lang.IndexOutOfBoundsException: Source does not fit in dest
        at java.util.Collections.copy(Collections.java:548)
        at backtracking2.Main.findSubsets(Main.java:61)
为什么?
6个回答

99

容量并不等于大小。您传递的大小参数只是为大小分配足够的内存,它并没有定义元素。这实际上是Collections.copy的一个有点傻的要求,但它确实存在。

Collections.copy JavaDocs中的关键部分:

目标列表的长度必须至少与源列表相同。如果它更长,则目标列表中剩余的元素不受影响。

您应该只需将List传递给ArrayList的构造函数即可完全复制所有List,从而避免出现问题。


10
我将其评为低分,因为将其添加到构造函数中将进行 [b]浅层复制[/b] 并且不同于深度复制。在原列表中操作元素也会影响“复制到”的列表。 - Boy
8
你的观点是错误的。请查看ArrayList的源代码,在调用toArrayArrays.copyOf时,会对列表进行深复制。在执行numbersCopy = new ArrayList<Integer>(numbers)后,修改任何一个列表都不会影响另一个列表。这显然会使构造函数的目的失去意义(而且它使用的是Collection而不是List)。 - pickypg
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - pickypg
2
我不知道“new”不会影响彼此的列表。对于我的错误表示抱歉... - Boy
深拷贝更好地定义为“对新对象的任何部分进行更改都不会影响旧对象”,因此“仅列表位”的深拷贝并没有实际意义。如果原始对象的任何部分是可变的,则新旧对象可能会相互影响,因此这将不是深拷贝。但是,在列表中的不可变元素(例如本问题中的Integer)的情况下,浅拷贝和深拷贝之间在功能上没有区别。 - paxdiablo

30

这是一个非常好的问题,它几乎肯定与设置集合容量时不一定分配底层对象有关。但是,当您可以采取以下方式时,为什么要这样做:

ArrayList <Integer> numbersCopy = new ArrayList<Integer>(numbers);

13
它复制参考资料。 - temirbek
@temirbek,不会的。我刚刚测试过了,而且源代码(http://hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/share/classes/java/util/ArrayList.java#l150)说“Arrays.copyOf()”意味着它将是未引用的副本。 - Farid
@Snedden27:是的,浅拷贝,但在这种情况下并不重要,因为Integer是不可变的。 - paxdiablo

6
构造函数ArrayList(Collection<? extends E> c)将会把c中的每个元素复制到新创建的实例中,从而把numbers复制到numbersCopy中。这与numbersCopy.addAll(numbers)是相同的,这也是你需要的。 Collection.copy要求dest数组足够大,以容纳所有来自source数组的元素,这是有道理的。类似的类比是C函数memcpy等。

1

您也可以使用Collections.addAll,例如我们需要将List1复制到List2中,那么

List2.addAll(List1);

这里的文件将被添加,如果您希望它更加高效,则确保在将list1的项添加到list2之前清除list2,像这样:

list2.clear();

1
在使用Collections.copy()方法创建一个ArrayList以复制另一个ArrayList时,我们需要确保目标List包含与源List相同数量的值(不仅仅是相同的大小)。例如,如果源ArrayList具有值[Red,Blue,Green],则目标ArrayList也应该包含与之相同数量的元素,如[Orange,Yellow,Blue]。如果我们创建一个与源ArrayList大小相同的ArrayList,它将会产生OutOfBounds异常。

-1
在Java 8+中
List<Integer> numbersCopy = numbers.stream().collect(Collectors.toList());

在 Java 10+ 中更容易。

List<Integer> numbersCopy = List.copyOf(numbers);

List.copyOf() 返回一个包含给定集合元素的不可修改 List。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接