Как клонировать 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 ().
Я лично добавил бы конструктор к Dog:
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 2nd Edition, п. 11: переопределить клон разумно
учитывая все проблемы, связанные с Cloneable, можно с уверенностью сказать что другие интерфейсы не должны расширять его, и что классы разработанный для наследования (пункт 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
называется ссылка на метод. Он создает объекты функции, которые вызывают конструктор на 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.*;
.
коллектор ArrayList
s
коллектор из последнего примера можно превратить в метод 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), которая глубоко клонирует объекты. Объекты не должны реализовывать интерфейс Cloneable. Эффективно, эта библиотека может клонировать любые объекты java. Его можно использовать, т. е. в реализациях кэша, если вы не хотите, чтобы кэшированный объект был изменен или когда вы хотите создать глубокую копию объектов.
Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);
проверьте это в https://github.com/kostaskougios/cloning
вам нужно будет клонировать ArrayList
вручную (путем итерации по нему и копирования каждого элемента в новый ArrayList
), поскольку clone()
не будет делать это за вас. Причина этого в том, что объекты, содержащиеся в ArrayList
не может реализовать Clonable
сами.
редактировать: ... именно это и делает кодекс Вархана.
противный способ сделать это с отражением. Что-то вроде этого сработало для меня.
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 () для векторного obj или arrailist obj....
простой способ с помощью 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);
Дайте мне знать, если это не сработает для вас.