【问题标题】:java.lang.IndexOutOfBoundsException: Source does not fit in destjava.lang.IndexOutOfBoundsException:源不适合目标
【发布时间】: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)

为什么?

【问题讨论】:

    标签: java arraylist collections indexoutofboundsexception


    【解决方案1】:

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

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

    【讨论】:

    【解决方案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();

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-12-05
            • 1970-01-01
            • 1970-01-01
            • 2011-05-16
            • 1970-01-01
            • 1970-01-01
            • 2017-04-16
            • 2011-05-19
            相关资源
            最近更新 更多