Collections.copy проблема - PullRequest
4 голосов
/ 12 мая 2011

Я хочу, чтобы b1 и b2 имели свои собственные наборы элементов, тогда b1 и b2 должны иметь свои собственные элементы в памяти, чтобы при изменении b1 / b2 другие не затрагивались.

buffer - это ArrayList, содержащий много элементов

List<Integer>  b1 = new ArrayList<Integer>(buffer.size()) ;
List<Integer>  b2 = new ArrayList<Integer>(buffer.size()) ) ;
Collections.copy(b1, buffer);
Collections.copy(b2, buffer);

Я получаю это исключение:

Exception in thread "main"
java.lang.IndexOutOfBoundsException: Source does not fit in dest
    at java.util.Collections.copy(Collections.java:531)
    at Trees.containsSumPrint(Trees.java:243)
    at Trees.main(Trees.java:125)

Ответы [ 3 ]

10 голосов
/ 12 мая 2011

Конструктор ArrayList(int) дает List, который имеет размер 0, он только гарантирует, что элементы n могут быть добавлены до того, как ему потребуется перераспределить базовый массив.

Лучший способ скопироватьсписки:

b1.addAll(buffer);
b2.addAll(buffer);

Семантика та же, что и при первом добавлении buffer.size() нулей в каждый массив и вызове Collections.copy(b1,buffer);


Если вы хотите глубокуюскопировать (элементы также скопированы) вам придется обрабатывать каждый элемент отдельно

for(MyObject obj:buffer){
    b1.add(obj.clone());
    b2.add(obj.clone());
}
1 голос
/ 12 мая 2011

Вы хотите глубокую копию каждого элемента.Не существует стандартного способа добиться этого, потому что глубокое копирование может включать копирование вложенных ссылок (коллекций) других объектов.Лучший способ сделать это - создать конструктор копирования, у java.lang.Integer он есть!Поэтому я думаю, что вы должны сделать что-то вроде:

List<Integer> buffer = Arrays.asList(new Integer[] { 0, 1, 2, 3, 4 });
List<Integer> b1 = new ArrayList<Integer>();
List<Integer> b2 = new ArrayList<Integer>();

for (Integer element : buffer) {
    b1.add(new Integer(element));
    b2.add(new Integer(element));
}

Это на самом деле создает две копии, по одной в каждом списке целей.Если один из списков может содержать исходные элементы, просто выполните:

for (Integer element : buffer) {
    b1.add(new Integer(element));
    b2.add(element);
}

Обратите внимание, что также существует клонируемый интерфейс.Я советую не использовать это, потому что легко делать ошибки с указанными классами, коллекциями и подклассами.Конструктор копирования гораздо проще понять.См. эту страницу для подтверждения.

РЕДАКТИРОВАТЬ: при повторном чтении, возможно, вам не нужны глубокие копии, в этом случае вы можете использовать метод addAll, как описано другими,Это позволит вам создать несколько коллекций одинаковых экземпляров объекта.Затем вы можете изменить содержимое / порядок объектов в одной коллекции, не затрагивая другие коллекции.Однако, если вы измените экземпляр объекта, это, очевидно, будет отражено и во всех других коллекциях.

Кроме того, StephenC справедливо указывает, что мой приведенный выше пример является ненормальным.Я согласен, что никто бы никогда не стал «глубоко копировать» целые числа, как обычно, но это имело бы смысл для пользовательских объектов, содержащих коллекции / ссылки, которые, как я думал, были проблемой здесь.

1 голос
/ 12 мая 2011

Collections.copy(...) javadoc говорит следующее:

"Копирует все элементы из одного списка в другой. После операции, индекс каждого скопированногоэлемент в списке адресатов будет идентичен его индексу в исходном списке. Список адресатов должен быть не меньше длины исходного списка. Если он длиннее, остальные элементы в списке адресатов не затрагиваются.. ".

Конструктор ArrayList(int) создает пустой список, чья емкость (не размер!) Задается аргументом.

Так какb1 изначально пуст, копирование непустого списка в него (с использованием copy) не удастся, поскольку предварительное условие (выделено жирным шрифтом) не выполняется в общем случае (*).

В основном, Collections.copy(...) это неправильный метод для использования.

То, что вы действительно должны делать, это:

List<Integer> b1 = new ArrayList<Integer>(buffer.size());
List<Integer> b2 = new ArrayList<Integer>(buffer.size());
b1.addAll(buffer);
b2.addAll(buffer);

Я предполагаю, что вы не на самом деле хотите создать новые экземпляры элементов списка.Если вы это сделаете, я должен указать, что создание новых экземпляров Integer объектов - пустая трата времени, поскольку Integer (как и другие классы-оболочки и String) является неизменным классом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...