java.lang.IndexOutOfBoundsException:源不适合目标

Posted

技术标签:

【中文标题】java.lang.IndexOutOfBoundsException:源不适合目标【英文标题】:java.lang.IndexOutOfBoundsException: Source does not fit in dest 【发布时间】:2011-09-03 02:37:03 【问题描述】:

关于以下代码:

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)

为什么?

【问题讨论】:

【参考方案1】:

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

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

【讨论】:

它复制参考 @temirbek,不,不会。我刚刚测试了它加上源代码(hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/…)说Arrays.copyOf()意味着它将是未引用的副本 @Snedden27:是的,肤浅的,但在这种情况下并不重要,因为Integer 是不可变的。【参考方案2】:

容量不等于大小。您传入的大小参数只是为大小分配足够的内存。它实际上并没有定义元素。 Collections.copy 实际上是一种愚蠢的要求,但它仍然是一个。

关键部分来自Collections.copy JavaDocs:

目标列表必须至少与源列表一样长。如果更长,则目标列表中的其余元素不受影响。

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

【讨论】:

我降级了,因为将它添加到构造函数中会进行 [b]shallow[/b] 复制,并且与深复制不同。操作原始列表中的元素,也会在“复制到”列表中操作它们 @Boy 你的观点不正确。请参阅source code for ArrayList,其中通过调用toArrayArrays.copyOf 生成列表 的深层副本。在numbersCopy = new ArrayList&lt;Integer&gt;(numbers) 之后对任一列表所做的更改不会 影响另一个。这肯定会破坏构造函数的目的(无论如何它需要Collection 而不是List)。 @Boy 除非您明白 元素本身 也没有为真正的深层副本重建?由于 Java 不需要复制构造函数,因此这几乎是不可能的要求,而 Collections.copy does not perform either. 我不知道“新”不会影响彼此的列表。抱歉说错了…… 深拷贝更好地定义为“对新对象任何部分的任何更改都不会影响旧对象”,因此“仅列表位”的深拷贝并没有真正有道理。如果原始对象的任何部分是可变的,那么新对象和旧对象可能会相互影响,因此不会是深层副本。但是,对于列表中的不可变元素(如本问题中的Integer),浅拷贝和深拷贝在功能上没有区别。【参考方案3】:

构造函数ArrayList(Collection&lt;? extends E&gt; c)会将c中的每个元素复制到新创建的实例中,从而将numbers复制到numbersCopy中。也和numbersCopy.addAll(numbers)一样,正是你需要的。

Collection.copy 要求dest 数组足够大以容纳source 数组中的所有元素是有道理的。类似的类比是C函数memcpy等。

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

在 java 8 + 中

List<Integer> numbersCopy = numbers.stream().collect(Collectors.toList());

在 java 10+ 中更容易

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

List.copyOf() 返回一个包含给定 Collection 元素的 unmodifiable 列表。

【讨论】:

【参考方案6】:

您也可以使用 Collections.addAll 像假设我们需要将 List1 复制到 List2,那么 List2.addAll(List1); 这里将添加文件,如果您希望它更高效,请确保在添加 list1 的项目之前清除 list2,如下所示, list2.clear();

【讨论】:

以上是关于java.lang.IndexOutOfBoundsException:源不适合目标的主要内容,如果未能解决你的问题,请参考以下文章