Как клонировать ArrayList, а также клонировать его содержимое?
как я могу клонировать ArrayList, а также клонировать предметы в Java?
например у меня есть:
ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....
и я ожидал бы, что объекты в clonedList не такие же, как в списке собак.
17 ответов:
вам нужно будет перебирать элементы и клонировать их один за другим, помещая клоны в массив результатов по мере прохождения.
public static List<Dog> cloneList(List<Dog> list) { List<Dog> clone = new ArrayList<Dog>(list.size()); for (Dog item : list) clone.add(item.clone()); return clone; }для этого, очевидно, вам нужно будет получить объект Dog для реализации интерфейса Cloneable и метода clone ().
Я, лично, хотел бы добавить конструктор для собаки:
class Dog { public Dog() { ... } // Regular constructor public Dog(Dog dog) { // Copy all the fields of Dog. } }затем просто повторите (как показано в ответе Вархана):
public static List<Dog> cloneList(List<Dog> dogList) { List<Dog> clonedList = new ArrayList<Dog>(dogList.size()); for (Dog dog : dogList) { clonedList.add(new Dog(dog)); } return clonedList; }Я считаю, что преимущество этого заключается в том, что вам не нужно возиться с сломанным клонируемым материалом в Java. Он также соответствует способу копирования коллекций Java.
другой вариант может быть написать свой собственный icloneable интерфейс и использовать его. Таким образом, вы можете написать общий метод клонирования.
все стандартные коллекции имеют конструкторы копирования. Использовать их.
List<Double> original = // some list List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy
clone()был разработан с несколькими ошибками (см. этот вопрос), так что лучше избегать его.С эффективная Java 2-е издание, п. 11: переопределить клон разумно
учитывая все проблемы, связанные с клонированием, можно с уверенностью сказать что другие интерфейсы не должны расширять его, и что классы разработанный для наследования (пункт 17) не следует его реализовывать. Потому что его много недостатков, некоторые опытные программисты просто предпочитают никогда не делать переопределите метод clone и никогда не вызывайте его, за исключением, возможно, копирование массивов. Если вы создаете класс для наследования, имейте в виду, что если вы решили не предоставлять хорошо защищенный метод клонирования, он будет невозможно для подклассов реализовать Cloneable.
в этой книге также описаны многие преимущества конструкторов копирования есть более клонируемый / клон.
- они не полагаются на рискованное создание экстралингвистических объектов механизм
- они не требуют неисполнимого соблюдения тонко документированных конвенций
- они не конфликтуют с правильным использованием конечных полей
- они не бросают ненужные проверенные исключения
- они не требуют бросков.
рассмотрим еще одно преимущество использования конструктора копирования: предположим, что вы есть
HashSet s, и вы хотите скопировать его какTreeSet. Метод clone не может предложить эту функциональность, но это легко с конструктором преобразования:new TreeSet(s).
Java 8 предоставляет новый способ вызова конструктора копирования или метода клонирования на элементе dogs элегантно и компактно:потоки,лямбда и коллекторами.
конструктор копирования:
List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());выражение
Dog::newназывается a ссылка на метод. Он создает объекты функции, которые вызывают конструктор наDogкоторая принимает другую собаку как аргумент.метод clone:
List<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toList());
получать
ArrayListв результатеили, если вы должны получить
ArrayListобратно (в случае, если вы хотите изменить его позже):ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));
обновить список на месте
если вам не нужно сохранить исходное содержимое
dogsсписок вы можете использоватьreplaceAllметод и обновить список на месте вместо этого:dogs.replaceAll(Dog::new);
все примеры предполагают
import static java.util.stream.Collectors.*;.
коллектор
ArrayListsколлектор из последнего примера может быть превращен в метод util. Поскольку это такая обычная вещь, я лично люблю, чтобы она была короткой и красивой. Вот так:
ArrayList<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList()); public static <T> Collector<T, ?, ArrayList<T>> toArrayList() { return Collectors.toCollection(ArrayList::new); }
Примечание
CloneNotSupportedException:чтобы это решение работало
cloneметодDogне должен объявить, что он бросаетCloneNotSupportedException. Причина в том, что аргументmapне разрешается выбрасывать какие-либо проверенные исключения.такой:
// Note: Method is public and returns Dog, not Object @Override public Dog clone() /* Note: No throws clause here */ { ...это не должно быть большой проблемой, так как это в любом случае лучшая практика. (Effectice На Java например дает такой совет.)
спасибо Густаво за то, что отметил это.
PS:
если вы найдете его красивее, вы можете вместо этого использовать синтаксис ссылки на метод, чтобы сделать точно то же самое:
List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
в основном есть три способа без итерации вручную,
1 с помощью конструктора
ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);2 с помощью
addAll(Collection<? extends E> c)ArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(); clonedList.addAll(dogs);3 с помощью
addAll(int index, Collection<? extends E> c)методintпараметрArrayList<Dog> dogs = getDogs(); ArrayList<Dog> clonedList = new ArrayList<Dog>(); clonedList.addAll(0, dogs);NB: поведение этих операций будет неопределенным, если указанная коллекция будет изменена во время выполнения операции.
Я думаю, что текущий зеленый ответ плох , почему спросите вы?
- он может потребовать, чтобы добавить много кода
- это требует от вас, чтобы перечислить все списки, которые будут скопированы и сделать это
способ сериализации также плох imo, возможно, вам придется добавить сериализуемый повсюду.
Так каково же решение:
библиотека глубокого клонирования Java клонирование библиотека небольшой, библиотека java с открытым исходным кодом (Apache licence), которая глубоко клонирует объекты. Объекты не должны реализовать интерфейс Cloneable. Эффективно, эта библиотека может клонировать любые объекты java. Его можно использовать, например, в реализациях кэша, если вы не хотите, чтобы кэшированный объект был изменен или когда вы хотите создать глубокую копию объектов.
Cloner cloner=new Cloner(); XX clone = cloner.deepClone(someObjectOfTypeXX);проверьте его на https://github.com/kostaskougios/cloning
вам нужно будет клонировать
ArrayListвручную (путем итерации по нему и копирования каждого элемента в новыйArrayList), посколькуclone()не будет делать это за вас. Причина этого заключается в том, что объекты, содержащиеся вArrayListне может реализоватьClonableсами.Edit: ... и это именно то, что делает код Вархана.
противный способ сделать это с отражением. Что-то вроде этого сработало для меня.
public static <T extends Cloneable> List<T> deepCloneList(List<T> original) { if (original == null || original.size() < 1) { return new ArrayList<>(); } try { int originalSize = original.size(); Method cloneMethod = original.get(0).getClass().getDeclaredMethod("clone"); List<T> clonedList = new ArrayList<>(); // noinspection ForLoopReplaceableByForEach for (int i = 0; i < originalSize; i++) { // noinspection unchecked clonedList.add((T) cloneMethod.invoke(original.get(i))); } return clonedList; } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { System.err.println("Couldn't clone list due to " + e.getMessage()); return new ArrayList<>(); } }
вот решение с использованием общего типа шаблона:
public static <T> List<T> copyList(List<T> source) { List<T> dest = new ArrayList<T>(); for (T item : source) { dest.add(item); } return dest; }
для вас объекты переопределить метод clone ()
class You_class { int a; @Override public You_class clone() { You_class you_class = new You_class(); you_class.a = this.a; return you_class; } }и звонок .clone () для векторного объекта или объекта ArraiList....
простой способ с помощью commons-lang-2.3.jar, что библиотека java для клонирования списка
ссылке скачать commons-lang-2.3.банку
Как использовать
oldList......... List<YourObject> newList = new ArrayList<YourObject>(); foreach(YourObject obj : oldList){ newList.add((YourObject)SerializationUtils.clone(obj)); }Я надеюсь, что это может быть полезно.
: D
пакета
import org.apache.commons.lang.SerializationUtils;есть метод
SerializationUtils.clone(Object);пример
this.myObjectCloned = SerializationUtils.clone(this.object);
Я только что разработал lib, который способен клонировать объект сущности и java.утиль.Объект списка. Просто скачайте банку вhttps://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U и использовать статический метод cloneListObject (List list). Этот метод клонирует не только список, но и все элементы сущности.
Я всегда использовал эту опцию:
ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
Я нашел способ, вы можете использовать JSON сериализовать/восстановить список. Сериализованный список содержит никаких ссылок на исходный объект, когда необходимо выполнить десериализацию.
С помощью gson:
List<CategoryModel> originalList = new ArrayList<>(); // add some items later String listAsJson = gson.toJson(originalList); List<CategoryModel> newList = new Gson().fromJson(listAsJson, new TypeToken<List<CategoryModel>>() {}.getType());вы можете сделать это с помощью jackson и любой другой библиотеки json тоже.
Я думаю, что нашел очень простой способ сделать глубокую копию ArrayList. Предполагая, что вы хотите скопировать строку ArrayList arrayA.
ArrayList<String>arrayB = new ArrayList<String>(); arrayB.addAll(arrayA);Дайте мне знать, если это не сработает для вас.
Comments