java.lang.IndexOutOfBoundsException: Quelle passt nicht in dest


74

Auf dem folgenden Code:

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

Ich erhalte den Fehler:

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)

Warum?

Antworten:


93

Die Kapazität entspricht nicht der Größe. Der Größenparameter, den Sie übergeben, weist einfach genügend Speicher für die Größe zu. Es werden keine Elemente definiert. Es ist eigentlich eine Art dumme Anforderung von Collections.copy, aber es ist trotzdem eine.

Der Schlüsselteil aus den Collections.copyJavaDocs :

Die Zielliste muss mindestens so lang sein wie die Quellliste. Wenn es länger ist, bleiben die verbleibenden Elemente in der Zielliste unberührt.

Sie sollten das einfach an den Konstruktor Listdes ArrayList'übergeben, um alle zu kopieren List, um das Problem insgesamt zu vermeiden.


8
Ich habe dies herabgestuft, da das Hinzufügen zum Konstruktor eine [b] flache [/ b] Kopie ergibt und nicht mit einer tiefen Kopie identisch ist. Wenn Sie die Elemente in der ursprünglichen Liste bearbeiten, werden sie auch in der Liste "kopiert nach" bearbeitet
Boy

7
@ Boy Dein Punkt ist falsch. Siehe den Quellcode für ArrayList, in dem eine tiefe Kopie der Liste über einen Aufruf von toArrayund erstellt wird Arrays.copyOf. Änderungen, die an einer der folgenden Listen vorgenommen werden, wirken numbersCopy = new ArrayList<Integer>(numbers)sich nicht auf die andere aus. Das würde sicherlich den Zweck des Konstruktors zunichte machen (und es braucht ein Collectionund Listsowieso kein ).
Pickypg

1
@Boy Es sei denn, Sie kommen zu der Tatsache, dass die Elemente selbst nicht auch für eine echte tiefe Kopie rekonstruiert werden? Da Java keine Kopierkonstruktoren benötigt, wäre dies eine nahezu unmögliche Anforderung, die Collections.copyauch keine Leistung erbringt .
Pickypg

2
Ich wusste nicht, dass das 'Neue' die Liste der anderen nicht beeinflusst. Tut mir leid, dass ich falsch
Boy

Eine tiefe Kopie ist besser definiert als "jede Änderung an einem Teil des neuen Objekts hat keine Auswirkungen auf das alte Objekt", daher ist eine tiefe Kopie von "nur das Listenbit" nicht wirklich sinnvoll. Wären Teile des ursprünglichen Objekts veränderbar, könnten sich das neue und das alte Objekt gegenseitig beeinflussen, sodass dies keine tiefe Kopie wäre. Bei unveränderlichen Elementen in der Liste (wie Integerin dieser Frage) gibt es jedoch keinen Funktionsunterschied zwischen einer flachen und einer tiefen Kopie.
paxdiablo

25

Das ist eine sehr gute Frage und hat mit ziemlicher Sicherheit damit zu tun, dass beim Festlegen einer Sammlungskapazität nicht unbedingt die zugrunde liegenden Objekte zugewiesen werden. Warum tun Sie dies jedoch so, wenn Sie nur:

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

11
es kopiert Referenz
Temirbek

@Temirbek, nein wird es nicht. Ich habe es gerade getestet und der Quellcode ( hg.openjdk.java.net/jdk7/modules/jdk/file/a37326fa7f95/src/… ) besagt, Arrays.copyOf()dass es sich um eine nicht referenzierte Kopie handelt
Farid,

@ Snedden27: ja, flach, aber es spielt in diesem Fall keine Rolle, da Integeres unveränderlich ist.
paxdiablo

5

Der Konstruktor ArrayList(Collection<? extends E> c)kopiert alle Elemente aus cin die neu erstellte Instanz und kopiert sie numbersin numbersCopy. Es ist das gleiche wie numbersCopy.addAll(numbers)auch, was wirklich das ist, was Sie brauchen.

Es ist sinnvoll, Collection.copydass das destArray groß genug sein muss, um alle Elemente des sourceArrays aufzunehmen. Eine ähnliche Analogie ist die C-Funktion memcpyund dergleichen.


1

Während eines Erstellen einer ArrayListandere kopieren , ArrayListindem Collections.copy()Methode, müssen wir sicherstellen , dass das Ziel Listgleiche Anzahl von Werten (nicht nur gleiche Größe) als Quelle enthält List. Wenn die Quelle beispielsweise ArrayListdie Werte [Rot, Blau, Grün] hat, sollte das Ziel ArrayListauch die gleiche Anzahl von Elementen wie [Orange, Gelb, Blau] enthalten. Wenn wir ein Element ArrayListmit der gleichen Größe wie die Quelle erstellen ArrayList, gibt es eine OutOfBoundsAusnahme.


1

Sie können auch Collections.add verwenden. Angenommen, wir müssen List1 nach List2 kopieren. List2.addAll(List1); Hier werden die Dateien hinzugefügt. Wenn Sie dies effizienter wünschen, müssen Sie die Liste2 löschen, bevor Sie die Elemente von list1 wie folgt hinzufügen. list2.clear();


-1

In Java 8 +

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

In Java 10+ ist es einfacher

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

Liste .copyOf()gibt eine unmodifiableListe zurück, die die Elemente der angegebenen Sammlung enthält.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.