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,其中通过调用toArray
和Arrays.copyOf
生成列表 的深层副本。在numbersCopy = new ArrayList<Integer>(numbers)
之后对任一列表所做的更改不会 影响另一个。这肯定会破坏构造函数的目的(无论如何它需要Collection
而不是List
)。
@Boy 除非您明白 元素本身 也没有为真正的深层副本重建?由于 Java 不需要复制构造函数,因此这几乎是不可能的要求,而 Collections.copy
does not perform either.
我不知道“新”不会影响彼此的列表。抱歉说错了……
深拷贝更好地定义为“对新对象任何部分的任何更改都不会影响旧对象”,因此“仅列表位”的深拷贝并没有真正有道理。如果原始对象的任何部分是可变的,那么新对象和旧对象可能会相互影响,因此不会是深层副本。但是,对于列表中的不可变元素(如本问题中的Integer
),浅拷贝和深拷贝在功能上没有区别。【参考方案3】:
构造函数ArrayList(Collection<? extends E> 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]。如果我们创建一个具有相同大小的 ArrayList
源ArrayList
的那个,它会给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:源不适合目标的主要内容,如果未能解决你的问题,请参考以下文章