У меня есть файл, ArrayList
и я хочу его точно скопировать. Я использую служебные классы, когда это возможно, исходя из предположения, что кто-то потратил некоторое время на их исправление. Естественно, я получаю Collections
класс, содержащий метод копирования.
Предположим, у меня есть следующее:
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
List<String> b = new ArrayList<String>(a.size());
Collections.copy(b,a);
Это не удается, потому что в основном он думает, что b
недостаточно велик, чтобы его удержать a
. Да, я знаю, что у b
него размер 0, но теперь он должен быть достаточно большим, не так ли? Если мне нужно b
сначала заполнить , то это Collections.copy()
станет для меня совершенно бесполезной функцией. Итак, кроме программирования функции копирования (что я собираюсь сделать сейчас), есть ли правильный способ сделать это?
java
list
collections
copy
Джаспер Этаж
источник
источник
Ответы:
Вызов
List<String> b = new ArrayList<String>(a);
создает неглубокую копию
a
внутриb
. Все элементы будут существовать внутриb
в том же порядке, в котором они были внутриa
(при условии, что это был порядок).Точно так же вызов
// note: instantiating with a.size() gives `b` enough capacity to hold everything List<String> b = new ArrayList<String>(a.size()); Collections.copy(b, a);
также создает неглубокую копию
a
внутриb
. Если первый параметр,b
не имеет достаточной емкости (не размера), чтобы содержать всеa
элементы, то он выдаст файлIndexOutOfBoundsException
. Ожидается, что для работы не потребуется никаких выделенийCollections.copy
, и если они есть, то это исключение будет выдано. Это оптимизация - требовать, чтобы скопированная коллекция была предварительно выделена (b
), но я обычно не думаю, что эта функция того стоит из-за необходимых проверок с учетом альтернативных конструкторов, подобных показанной выше, которые не имеют странных побочных эффектов.Чтобы создать глубокую копию, с
List
помощью любого механизма нужно было бы хорошо знать базовый тип. В случаеString
s, которые неизменяемы в Java (и .NET в этом отношении), вам даже не нужна глубокая копия. В случаеMySpecialObject
, вам нужно знать, как сделать его глубокую копию, и это не общая операция.Примечание. Первоначально принятый ответ был лучшим результатом для
Collections.copy
Google, и он был совершенно неверным, как указано в комментариях.источник
b
имеет емкость 3, но размер 0. Тот факт, чтоArrayList
есть какая-то буферная емкость, является деталью реализации - она не является частьюList
интерфейса, поэтомуCollections.copy(List, List)
не использует ее. Это было бы некрасиво для частного случаяArrayList
.Как указал MrWiggles, использование конструктора ArrayList, который принимает коллекцию, является способом в приведенном примере.
Для более сложных сценариев (которые вполне могут включать ваш реальный код) вы можете найти коллекции в Guava полезными.
источник
Просто делать:
List a = new ArrayList(); a.add("a"); a.add("b"); a.add("c"); List b = new ArrayList(a);
ArrayList имеет конструктор, который примет другую коллекцию для копирования элементов из
источник
String
объекты неизменяемы.Ответ Стивена Катулки (принятый ответ) неверен (вторая часть). Он объясняет, что
Collections.copy(b, a);
делает глубокую копию, чего не делает. И то,new ArrayList(a);
и другое, иCollections.copy(b, a);
только мелкую копию. Разница в том, что конструктор выделяет новую память, аcopy(...)
не выделяет , что делает его подходящим в случаях, когда вы можете повторно использовать массивы, так как там он дает преимущество в производительности.Стандартный API Java пытается препятствовать использованию глубоких копий, так как было бы плохо, если бы новые кодировщики использовали это на регулярной основе, что также может быть одной из причин, по которой
clone()
не является общедоступным по умолчанию.Исходный код для
Collections.copy(...)
можно увидеть в строке 552 по адресу: http://www.java2s.com/Open-Source/Java-Document/6.0-JDK-Core/Collections-Jar-Zip-Logging-regex/java/util/ Collections.java.htmЕсли вам нужна глубокая копия, вам нужно перебрать элементы вручную, используя цикл for и clone () для каждого объекта.
источник
Самый простой способ скопировать список - передать его конструктору нового списка:
List<String> b = new ArrayList<>(a);
b
будет мелкой копиейa
Глядя на источник
Collections.copy(List,List)
(я никогда его раньше не видел), похоже, он предназначен для копирования индекса элементов по индексу. использованиеList.set(int,E)
таким образом элемента 0 приведет к перезаписи элемента 0 в целевом списке и т. д. Не особо ясно из документации, которую я должен был бы признать.List<String> a = new ArrayList<>(a); a.add("foo"); b.add("bar"); List<String> b = new ArrayList<>(a); // shallow copy 'a' // the following will all hold assert a.get(0) == b.get(0); assert a.get(1) == b.get(1); assert a.equals(b); assert a != b; // 'a' is not the same object as 'b'
источник
List b = new ArrayList(a.size())
не устанавливает размер. Он устанавливает начальную емкость (сколько элементов может поместиться до того, как потребуется изменить размер). В этом случае более простой способ копирования:
List b = new ArrayList(a);
источник
Как упоминает Хойджуи. Выбранный ответ Стивена Катулки содержит неверный комментарий о Collections.copy. Автор, вероятно, принял это, потому что первая строка кода делала копию, которую он хотел. Дополнительный вызов Collections.copy просто копирует снова. (В результате копия происходит дважды).
Вот код, подтверждающий это.
public static void main(String[] args) { List<String> a = new ArrayList<String>(); a.add("a"); a.add("b"); a.add("c"); List<String> b = new ArrayList<String>(a); System.out.println("There should be no output after this line."); // Note, b is already a shallow copy of a; for (int i = 0; i < a.size(); i++) { if (a.get(i) != b.get(i)) { System.out.println("Oops, this was a deep copy."); // Note this is never called. } } // Now use Collections.copy and note that b is still just a shallow copy of a Collections.copy(b, a); for (int i = 0; i < a.size(); i++) { if (a.get(i) != b.get(i)) { System.out.println("Oops, i was wrong this was a deep copy"); // Note this is never called. } } // Now do a deep copy - requires you to explicitly copy each element for (int i = 0; i < a.size(); i++) { b.set(i, new String(a.get(i))); } // Now see that the elements are different in each for (int i = 0; i < a.size(); i++) { if (a.get(i) == b.get(i)) { System.out.println("oops, i was wrong, a shallow copy was done."); // note this is never called. } } }
источник
Большинство ответов здесь не осознают проблему, пользователь хочет иметь КОПИЮ элементов из первого списка во второй список, элементы целевого списка являются новыми объектами, а не ссылками на элементы исходного списка. (означает, что изменение элемента второго списка не должно изменять значения для соответствующего элемента исходного списка.) Для изменяемых объектов мы не можем использовать конструктор ArrayList (Collection), потому что он будет просто ссылаться на исходный элемент списка и не будет копировать. При копировании вам необходимо иметь клонатор списка для каждого объекта.
источник
Почему бы тебе просто не использовать
addAll
метод:List a = new ArrayList(); a.add("1"); a.add("abc"); List b = b.addAll(listA); //b will be 1, abc
даже если у вас есть существующие элементы в b или вы хотите отложить некоторые элементы после него, например:
List a = new ArrayList(); a.add("1"); a.add("abc"); List b = new ArrayList(); b.add("x"); b.addAll(listA); b.add("Y"); //b will be x, 1, abc, Y
источник
Если вы хотите скопировать ArrayList, скопируйте его, используя:
List b = new ArrayList(); b.add("aa"); b.add("bb"); List a = new ArrayList(b);
источник
Строки могут быть глубоко скопированы с помощью
List<String> b = new ArrayList<String>(a);
потому что они неизменны. Любой другой объект не -> вам нужно перебирать и копировать самостоятельно.
источник
b
указывает на один и тот же соответствующийString
объект вa
. Однако это не важно, потому что, как вы отметили,String
объекты неизменяемы.private List<Item> cloneItemList(final List<Item> items) { Item[] itemArray = new Item[items.size()]; itemArray = items.toArray(itemArray); return Arrays.asList(itemArray); }
источник
Любой другой объект не -> вам нужно перебирать и копировать самостоятельно.
Чтобы избежать этого, реализуйте Cloneable.
public class User implements Serializable, Cloneable { private static final long serialVersionUID = 1L; private String user; private String password; ... @Override public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { } return o; } }
....
public static void main(String[] args) { List<User> userList1 = new ArrayList<User>(); User user1 = new User(); user1.setUser("User1"); user1.setPassword("pass1"); ... User user2 = new User(); user2.setUser("User2"); user2.setPassword("pass2"); ... userList1 .add(user1); userList1 .add(user2); List<User> userList2 = new ArrayList<User>(); for(User u: userList1){ u.add((User)u.clone()); } //With this you can avoid /* for(User u: userList1){ User tmp = new User(); tmp.setUser(u.getUser); tmp.setPassword(u.getPassword); ... u.add(tmp); } */ }
источник
Следующий вывод иллюстрирует результаты использования конструктора копирования и Collections.copy ():
Copy [1, 2, 3] to [1, 2, 3] using copy constructor. Copy [1, 2, 3] to (smaller) [4, 5] java.lang.IndexOutOfBoundsException: Source does not fit in dest at java.util.Collections.copy(Collections.java:556) at com.farenda.java.CollectionsCopy.copySourceToSmallerDest(CollectionsCopy.java:36) at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:14) Copy [1, 2] to (same size) [3, 4] source: [1, 2] destination: [1, 2] Copy [1, 2] to (bigger) [3, 4, 5] source: [1, 2] destination: [1, 2, 5] Copy [1, 2] to (unmodifiable) [4, 5] java.lang.UnsupportedOperationException at java.util.Collections$UnmodifiableList.set(Collections.java:1311) at java.util.Collections.copy(Collections.java:561) at com.farenda.java.CollectionsCopy.copyToUnmodifiableDest(CollectionsCopy.java:68) at com.farenda.java.CollectionsCopy.main(CollectionsCopy.java:20)
Исходный код полной программы находится здесь: Копия списка Java . Но вывода достаточно, чтобы увидеть, как ведет себя java.util.Collections.copy ().
источник
И если вы используете google guava, однострочное решение будет
Это создает экземпляр списка изменяемых массивов.
источник
Поскольку Java 8 является нулевой безопасностью, вы можете использовать следующий код.
List<String> b = Optional.ofNullable(a) .map(list -> (List<String>) new ArrayList<>(list)) .orElseGet(Collections::emptyList);
Или с помощью коллектора
источник
Копирование не бесполезно, если вы представляете себе вариант использования для копирования некоторых значений в существующую коллекцию. Т.е. вы хотите перезаписать существующие элементы вместо вставки.
Пример: a = [1,2,3,4,5] b = [2,2,2,2,3,3,3,3,3,4,4,4,] a.copy (b) = [1,2,3,4,5,3,3,3,3,4,4,4]
Однако я бы ожидал, что будет метод копирования, который будет принимать дополнительные параметры для начального индекса исходной и целевой коллекции, а также параметр для count.
См. Ошибку Java 6350752
источник
Чтобы понять, почему Collections.copy () выдает исключение IndexOutOfBoundsException, хотя вы сделали резервный массив целевого списка достаточно большим (с помощью вызова size () в sourceList), см. Ответ Абхая Ядава в этом связанном вопросе: Как сделать скопируйте java.util.List в другой java.util.List
источник