java.lang.IndexOutOfBoundsException:源不适合dest


74

在以下代码上:

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)

为什么?

Answers:


93

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

Collections.copyJavaDocs的关键部分:

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

您应该只将传递ListArrayList的构造函数来复制所有,List以完全避免出现此问题。


8
我对此进行了降级,因为将其添加到构造函数中会执行[b] shallow [/ b]复制,并且不会与深度复制相同。操作原始列表中的元素,还将在“复制到”列表中对其进行操作
Boy

7
@男孩你的观点不正确。请参阅ArrayList源代码,其中通过调用和进行列表的深层复制。更改为任一列表发后也不会影响其他的。这肯定会违背构造函数的目的(并且需要a而不是任何方法)。toArrayArrays.copyOfnumbersCopy = new ArrayList<Integer>(numbers)CollectionList
pickypg

1
@Boy除非您发现元素本身也没有为真正的深层副本重建的事实?由于Java不需要复制构造函数,因此这几乎是不可能的要求,并且Collections.copy也不会执行
pickypg

2
我不知道“新”并不会影响彼此的名单。很抱歉不正确...
Boy

深层副本最好定义为“对新对象的任何部分进行任何更改都不会影响旧对象”,因此,“仅列出位”的深层副本实际上没有任何意义。如果原始对象的任何部分都可变,则新对象和旧对象可能会相互影响,因此不会构成深层副本。但是,对于列表中的不可变元素(如Integer本问题),浅表副本和深表副本之间在功能上没有区别。
paxdiablo

25

这是一个非常好的问题,并且几乎可以肯定地与以下事实有关:设置集合容量并不一定会分配基础对象,但是为什么您可以这样做呢?

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

11
它复制了参考
temirbek

@temirbek,不,不会。我刚刚对其进行了测试,并加上源代码(hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/…)表示Arrays.copyOf()这将是未引用的副本
Farid

@ Snedden27:是的,浅,但是在这种情况下没有关系,因为它Integer是不可变的。
paxdiablo

5

构造函数ArrayList(Collection<? extends E> c)会将每个元素从c复制numbers到新创建的实例中,从而复制到中numbersCopy。这是一样的numbersCopy.addAll(numbers)还有,这是你真的需要什么。

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


2

您还可以使用Collections.addAll之类的方法,假设我们需要将List1复制到List2,然后将 List2.addAll(List1); 在此处添加文件,如果您想提高效率,那么请确保在添加list1之前清除list2,例如这样, list2.clear();


1

创建一个ArrayList复制另一个ArrayListusingCollections.copy()方法时,我们需要确保目标List包含与source相同数量的值(不仅仅是大小)List。例如,如果source的ArrayList值为[Red,Blue,Green],则目标位置ArrayList还应包含相同数量的元素,例如[Orange,Yellow,Blue]。如果我们创建的ArrayList尺寸与source相同ArrayList,则会给出OutOfBounds异常。


-1

在Java 8 +

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

在Java 10+中更轻松

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.