Как клонировать ArrayList, а также клонировать его содержимое?

Как я могу клонировать ArrayList, а также клонировать его элементы на Java?

Например у меня есть:

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = ....something to do with dogs....

И я ожидал, что объекты в clonedList не такие же, как в списке собак.


person palig    schedule 03.04.2009    source источник
comment
Это уже обсуждалось в вопросе рекомендации по утилите глубокого клонирования   -  person Swiety    schedule 04.04.2009


Ответы (21)


Вам нужно будет перебирать элементы и клонировать их один за другим, по ходу помещая клоны в массив результатов.

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().

person Varkhan    schedule 03.04.2009
comment
Однако вы не можете сделать это в общих чертах. clone () не является частью интерфейса Cloneable. - person Michael Myers; 04.04.2009
comment
Но clone () защищен в Object, поэтому вы не можете получить к нему доступ. Попробуйте скомпилировать этот код. - person Michael Myers; 04.04.2009
comment
Все классы расширяют Object, поэтому они могут переопределить clone (). Для этого и нужен Cloneable! - person Stephan202; 04.04.2009
comment
Это хороший ответ. Cloneable - это на самом деле интерфейс. Однако у mmyers есть смысл в том, что метод clone () - это защищенный метод, объявленный в классе Object. Вам придется переопределить этот метод в своем классе Dog и самостоятельно копировать поля вручную. - person Jose; 04.04.2009
comment
@Jose: Да, вы могли бы сделать это с помощью определенного класса, который переопределил clone (), чтобы сделать его общедоступным. Но вы не можете сделать это в общих чертах; это моя точка зрения. - person Michael Myers; 04.04.2009
comment
@mmyers Моя плохая. Да, я знал, что Cloneable iface был изрядно испорчен, но не понимал до какой степени. - person Varkhan; 04.04.2009
comment
Кроме того, Cloneable - это просто интерфейс для подписи, например Serializable. Даже если вы перезапишите метод clone () в классе Object, если ваш класс не реализует Cloneable, компилятор javac выдаст ошибку. - person Jose; 04.04.2009
comment
@Jose: Ну, технически у вас нет необходимости для вызова super.clone () в вашем методе clone (), поэтому вам не обязательно реализовывать Cloneable. Видите, почему никому не нравится Cloneable? : D - person Michael Myers; 04.04.2009
comment
Идея интерфейса Cloneable - это `` контракт '': обещание разумно реализовать clone (). Это правда, что Dog нужно переопределить clone (), а затем реализовать интерфейс. - person Stephan202; 04.04.2009
comment
@mmyers Ты прав. Обычно это не работает, потому что интерфейс и метод не определены в одном и том же пространстве. Хорошая точка зрения. - person Jose; 04.04.2009
comment
Я говорю: создайте фабрику или конструктор, или даже просто статический метод, который будет принимать экземпляр Dog, вручную копировать поля в новый экземпляр и возвращать этот новый экземпляр. - person Jose; 04.04.2009
comment
@JoseChavez Да, это было бы лучше. Однако OP упоминает клонирование, которое может быть обязательным требованием. - person Varkhan; 04.04.2009
comment
Следует также отметить, что clone() не вызывает конструктор, что может вызвать некоторые проблемы для определенных классов. - person cdmckay; 04.02.2013
comment
Хорошей практикой было бы иметь конструктор в классе Dog, который принимает ровно 1 параметр - объект Dog - и клонировать с помощью этого конструктора. Но да ... никому не нравится клонирование :) - person milosmns; 15.04.2016
comment
Я предлагаю никогда не использовать функцию с именем clone. Всегда используйте функцию с именем deepClone или shallowClone. - person hyyou2010; 19.10.2017

Лично я бы добавил в 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;
}

Я считаю, что преимущество этого заключается в том, что вам не нужно возиться с неработающим материалом Cloneable в Java. Это также соответствует способу копирования коллекций Java.

Другой вариант - написать собственный интерфейс ICloneable и использовать его. Таким образом можно было бы написать общий метод клонирования.

person cdmckay    schedule 03.04.2009
comment
не могли бы вы быть более конкретными, скопировав все поля СОБАКИ. Я действительно не понимаю :( - person Dr. aNdRO; 23.04.2014
comment
Можно ли написать эту функцию для неопределенного объекта (вместо Dog)? - person Tobi G.; 15.02.2016
comment
@TobiG. Я не понимаю о чем ты. Вы хотите cloneList(List<Object>) или Dog(Object)? - person cdmckay; 15.02.2016
comment
@cdmckay Одна функция, которая работает для cloneList (Список ‹Object›), cloneList (Список ‹Dog›) и cloneList (Список ‹Cat›). Но вы не можете назвать универсальный конструктор, я думаю ...? - person Tobi G.; 17.02.2016
comment
@TobiG. Тогда как обычная функция клонирования? Вопрос не в этом. - person cdmckay; 17.02.2016
comment
Как указано в @helpermethod, это общий шаблон, который понятен и прост для понимания. - person milosmns; 15.04.2016
comment
Сладкий. Намного проще и практичнее, чем реализовать Clonable! - person Dmitry Moskovchenko; 09.03.2021

Все стандартные коллекции имеют конструкторы копирования. Используй их.

List<Double> original = // some list
List<Double> copy = new ArrayList<Double>(original); //This does a shallow copy

clone() был разработан с несколькими ошибками (см. этот вопрос), поэтому лучше избегай это.

Из Эффективное 2-е издание Java, пункт 11: Разумно переопределить клон

Учитывая все проблемы, связанные с Cloneable, можно с уверенностью сказать, что другие интерфейсы не должны его расширять и что классы, разработанные для наследования (совет 17), не должны его реализовывать. Из-за его многочисленных недостатков некоторые опытные программисты просто предпочитают никогда не переопределять метод клонирования и никогда не вызывать его, за исключением, возможно, копирования массивов. Если вы разрабатываете класс для наследования, имейте в виду, что если вы решите не предоставлять хорошо работающий защищенный метод клонирования, для подклассов будет невозможно реализовать Cloneable.

В этой книге также описаны многие преимущества конструкторов копирования по сравнению с Cloneable / clone.

  • Они не полагаются на подверженный риску механизм создания экстралингвистических объектов.
  • Они не требуют необоснованного соблюдения плохо задокументированных соглашений.
  • Они не противоречат правильному использованию полей final
  • Они не выбрасывают ненужные проверенные исключения
  • Они не требуют повязок.

Рассмотрим еще одно преимущество использования конструкторов копирования: предположим, у вас есть HashSet s, и вы хотите скопировать его как TreeSet. Метод clone не может предложить эту функцию, но это легко сделать с помощью конструктора преобразования: new TreeSet(s).

person Rose Perrone    schedule 10.04.2012
comment
Насколько мне известно, конструкторы копирования стандартных коллекций создают мелкую копию, а не глубокую копию. Заданный здесь вопрос требует подробного ответа. - person Abdull; 29.11.2012
comment
это просто неправильно, конструкторы копирования делают неглубокую копию - вся суть вопроса - person NimChimpsky; 13.02.2013
comment
Что правильно в этом ответе, так это то, что если вы не изменяете объекты в списке, добавление или удаление элементов не удаляет их из обоих списков. Это не так поверхностно, как простое задание. - person Noumenon; 15.08.2015

Java 8 предоставляет новый способ элегантного и компактного вызова конструктора копирования или метода клонирования для элемента Dog: Потоки, лямбды и сборщики.

Конструктор копирования:

List<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toList());

Выражение Dog::new называется справкой по методу . Он создает функциональный объект, который вызывает конструктор Dog, который принимает в качестве аргумента другую собаку.

Метод клонирования [1]:

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

Сборщик из последнего примера можно превратить в метод утилиты. Поскольку это обычное дело, мне лично нравится, чтобы оно было коротким и красивым. Нравится:

ArrayList<Dog> clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList());

public static <T> Collector<T, ?, ArrayList<T>> toArrayList() {
    return Collectors.toCollection(ArrayList::new);
}

[1] Примечание к 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());
person Lii    schedule 03.11.2015
comment
Видите ли вы какое-либо влияние на производительность этого способа, когда Dog (d) является конструктором копирования? List<Dog> clonedDogs = new ArrayList<>(); dogs.stream().parallel().forEach(d -> clonedDogs.add(new Dog(d))); - person SaurabhJinturkar; 29.07.2016
comment
@SaurabhJinturkar: Ваша версия не является потокобезопасной и не должна использоваться с параллельными потоками. Это потому, что вызов parallel вызывает одновременный вызов clonedDogs.add из нескольких потоков. Версии, в которых используется collect, являются поточно-ориентированными. Это одно из преимуществ функциональной модели потоковой библиотеки, один и тот же код можно использовать для параллельных потоков. - person Lii; 29.07.2016
comment
@SaurabhJinturkar: Кроме того, операция сбора выполняется быстро. Он делает почти то же самое, что и ваша версия, но также работает для параллельных потоков. Вы можете исправить свою версию, используя, например, параллельную очередь вместо списка массивов, но я почти уверен, что это будет намного медленнее. - person Lii; 29.07.2016
comment
Каждый раз, когда я пытаюсь использовать ваше решение, я получаю Unhandled exception type CloneNotSupportedException на d.clone(). Объявление исключения или его перехват не решают. - person Gustavo; 23.08.2016
comment
@Gustavo: Это почти наверняка потому, что объект, который вы клонируете (Dog в этом примере), не поддерживает клонирование. Вы уверены, что он реализует Clonable интерфейс? - person Lii; 23.08.2016
comment
@Lii Это так. Плюс это отменяет clone(). Мне пришлось изменить свой clone(), чтобы не было никаких исключений. - person Gustavo; 23.08.2016
comment
@Gustavo: А, теперь я понимаю, я думал, у вас исключение во время выполнения, но у вас есть ошибка компиляции. Да, увы, работать с проверенными исключениями вместе с потоками и лямбдами очень неудобно. Однако я считаю, что в этом случае это нормально, потому что я считаю, что лучшая практика при переопределении clone - это делать то, что вы сделали, и не объявлять исключение (поскольку вы все равно не планируете его бросать). Я добавлю к ответу примечание об этом. Спасибо! - person Lii; 23.08.2016
comment
@YogenRai: Нет, это не так. Ваша строка кода даст поверхностную копию списка; результатом будет новый список, но он будет содержать те же Dog объекты. исходный список не будет изменен, но любая будущая модификация собак содержимого приведет к изменению тех же собак, что и в источнике. Этот вопрос касается создания новых объектов собак в новом списке. Это то, что называется глубокой копией. - person Lii; 18.04.2017
comment
@Lii Я прав :) Я не заметил, что изменение какого-либо элемента в dogs и наоборот с клонированным списком отразится на них обоих. И, как отмечали другие, я думаю, что конструктор копирования будет лучшим вариантом для создания новой копии. Итак, наша ламда будет List<Dog> clonedList = dogs.stream().map(Dog::new).collect(Collectors.toList());, и у меня есть конструктор копирования в классе Dog. Но в любом случае спасибо - person Yogen Rai; 18.04.2017
comment
@YogenRai: Ты прав, лучше с копирующими конструкторами. Я добавлю это к ответу. - person Lii; 19.04.2017
comment
Для разработчиков Android: эта stream функция доступна только для API ›= 24 - person Behrouz.M; 12.05.2020

В основном есть три способа без итерации вручную,

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: поведение этих операций будет неопределенным, если указанная коллекция будет изменена во время выполнения операции.

person javatar    schedule 18.02.2015
comment
пожалуйста, обратите внимание, что все эти 3 варианта создают только мелкие копии списков - person electrobabe; 15.03.2016
comment
Это не глубокий клон, эти два списка сохраняют одни и те же объекты, просто скопированы только ссылки, но объекты Dog, после того как вы изменили любой список, следующий список будет иметь такое же изменение. donno y так много голосов за. - person Saorikido; 12.10.2016
comment
@ Neeson.Z Все методы создают глубокую копию списка и мелкие копии элемента списка. Если вы изменяете элемент списка, изменение будет отражено в другом списке, но если вы измените один из списка (например, удалив объект), другой список не изменится. - person Alessandro Teruzzi; 07.06.2018

Я думаю, что текущий зеленый ответ плохой, почему вы можете спросить?

  • Может потребоваться добавить много кода
  • Это требует, чтобы вы перечислили все копируемые списки и сделали это

Способ сериализации также плох, imo, вам, возможно, придется добавлять Serializable повсюду.

Итак, какое решение?

Библиотека глубокого клонирования Java Библиотека клонирования - это небольшая библиотека java с открытым исходным кодом (лицензия apache), которая выполняет глубокое клонирование объектов. Объекты не обязательно должны реализовывать интерфейс Cloneable. Фактически, эта библиотека может клонировать ЛЮБЫЕ объекты Java. Его можно использовать, например, в реализациях кеширования, если вы не хотите, чтобы кешированный объект изменялся или когда вы хотите создать глубокую копию объектов.

Cloner cloner=new Cloner();
XX clone = cloner.deepClone(someObjectOfTypeXX);

Проверьте это на https://github.com/kostaskougios/cloning.

person Cojones    schedule 07.08.2009
comment
Один недостаток этого метода заключается в том, что он использует отражение, которое может быть немного медленнее, чем решение Вархана. - person cdmckay; 21.06.2010
comment
Я не понимаю первого пункта, для чего требуется много кода. Библиотеке, о которой вы говорите, потребуется больше кода. Вопрос только в том, где вы его разместите. В противном случае я согласен, что специальная библиотека для такого рода вещей помогает .. - person nawfal; 07.08.2013

Я нашел способ, вы можете использовать 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.

person sagits    schedule 09.06.2016
comment
Я не знаю, почему люди проголосовали против этого ответа. Другие ответы должны реализовать clone () или изменить свои зависимости, чтобы включить новые библиотеки. Но библиотека JSon в большинство проектов уже включена. Я проголосовал за это. - person Satish; 22.03.2018
comment
@Satish Да, это единственный ответ, который мне помог, я не уверен, что не так с другими, но независимо от того, что я сделал, клонировал или использовал конструктор копирования, мой исходный список использовался для обновления, но в этом случае это не так. , так что спасибо автору! - person Parag Pawar; 19.12.2018
comment
Что ж, это правда, что это не чисто Java-ответ ради знаний, а эффективное решение для быстрого решения этой проблемы. - person marcRDZ; 07.08.2019
comment
отличный хак, экономит время - person mxml; 23.02.2020

Я всегда использовал эту опцию:

ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
person besartm    schedule 18.05.2018

Вам нужно будет клонировать ArrayList вручную (повторяя его и копируя каждый элемент в новый ArrayList), потому что clone() не сделает этого за вас. Причина в том, что объекты, содержащиеся в ArrayList, могут не реализовывать сами Clonable.

Изменить: ... и это именно то, что делает код Вархана.

person Stephan202    schedule 03.04.2009
comment
И даже если они это сделают, нет другого способа получить доступ к clone (), кроме отражения, и в любом случае это не гарантирует успеха. - person Michael Myers; 04.04.2009

для вас объекты переопределяют метод 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 () для объекта Vector или объекта ArraiList ....

person RN3KK Nick    schedule 10.09.2012

Гадкий способ - делать это с помощью рефлексии. Что-то вроде этого у меня сработало.

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<>();
    }
}
person milosmns    schedule 01.10.2015
comment
Аккуратный и неприятный трюк! Одна потенциальная проблема: если original содержит объекты разных классов, я думаю, cloneMethod.invoke завершится ошибкой с исключением, когда он будет вызван с неправильным типом объекта. По этой причине может быть лучше получить конкретный клон Method для каждого объекта. Или используйте метод клонирования на Object (но поскольку он защищен, в других случаях может произойти сбой). - person Lii; 24.08.2016
comment
Кроме того, я думаю, что было бы лучше выбросить исключение времени выполнения в предложении catch вместо того, чтобы возвращать пустой список. - person Lii; 24.08.2016

List<Dog> dogs;
List<Dog> copiedDogs = dogs.stream().map(dog -> SerializationUtils.clone(dog)).Collectors.toList());

Это будет глубоко копировать каждую собаку

person Raju K    schedule 27.11.2019

Некоторые другие альтернативы для копирования ArrayList как глубокой копии

Предупреждение 1 - использование внешнего пакета commons-lang3, метод SerializationUtils.clone ():

SerializationUtils.clone()

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

Пример мелкой копии:

List<Dog> dogs = getDogs(); // We assume it returns a list of Dogs
List<Dog> clonedDogs = new ArrayList<>(dogs);

А теперь вернемся к глубокой копии собак.

У класса Dog есть только изменяемые поля.

Класс собаки:

public class Dog implements Serializable {
    private String name;
    private int age;

    public Dog() {
        // Class with only mutable fields!
        this.name = "NO_NAME";
        this.age = -1;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Обратите внимание, что класс Dog реализует Serializable! Это позволяет использовать метод SerializationUtils.clone (dog)

Прочтите комментарии к основному методу, чтобы понять результат. Это показывает, что мы успешно создали глубокую копию ArrayList (). См. Ниже SerializationUtils.clone (dog) в контексте:

public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.setName("Buddy");
    dog1.setAge(1);

    Dog dog2 = new Dog();
    dog2.setName("Milo");
    dog2.setAge(2);

    List<Dog> dogs = new ArrayList<>(Arrays.asList(dog1,dog2));

    // Output: 'List dogs: [Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]'
    System.out.println("List dogs: " + dogs);

    // Let's clone and make a deep copy of the dogs' ArrayList with external package commons-lang3:
    List<Dog> clonedDogs = dogs.stream().map(dog -> SerializationUtils.clone(dog)).collect(Collectors.toList());
    // Output: 'Now list dogs are deep copied into list clonedDogs.'
    System.out.println("Now list dogs are deep copied into list clonedDogs.");

    // A change on dog1 or dog2 can not impact a deep copy.
    // Let's make a change on dog1 and dog2, and test this
    // statement.
    dog1.setName("Bella");
    dog1.setAge(3);
    dog2.setName("Molly");
    dog2.setAge(4);

    // The change is made on list dogs!
    // Output: 'List dogs after change: [Dog{name='Bella', age=3}, Dog{name='Molly', age=4}]'
    System.out.println("List dogs after change: " + dogs);

    // There is no impact on list clonedDogs's inner objects after the deep copy.
    // The deep copy of list clonedDogs was successful!
    // If clonedDogs would be a shallow copy we would see the change on the field
    // "private String name", the change made in list dogs, when setting the names
    // Bella and Molly.
    // Output clonedDogs:
    // 'After change in list dogs, no impact/change in list clonedDogs:\n'
    // '[Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]\n'
    System.out.println("After change in list dogs, no impact/change in list clonedDogs: \n" + clonedDogs);
}

Вывод:

List dogs: [Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]
Now list dogs are deep copied into list clonedDogs.
List dogs after change: [Dog{name='Bella', age=3}, Dog{name='Molly', age=4}]
After change in list dogs, no impact/change in list clonedDogs:
[Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]

Комментарий. Поскольку после изменения списка собак не происходит никаких изменений / изменений в списке clonedDogs, глубокая копия ArrayList успешна!

Alernative 2 - использование внешних пакетов не выполняется:

В классе Dog представлен новый метод clone (), который реализует, что Serializable удален по сравнению с альтернативой 1.

clone()

Класс собаки:

public class Dog {
    private String name;
    private int age;

    public Dog() {
        // Class with only mutable fields!
        this.name = "NO_NAME";
        this.age = -1;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    /**
     * Returns a deep copy of the Dog
     * @return new instance of {@link Dog}
     */
    public Dog clone() {
        Dog newDog = new Dog();
        newDog.setName(this.name);
        newDog.setAge(this.age);
        return newDog;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Прочтите комментарии к основному методу ниже, чтобы понять результат. Это показывает, что мы успешно создали глубокую копию ArrayList (). См. Ниже метод clone () в контексте:

public static void main(String[] args) {
    Dog dog1 = new Dog();
    dog1.setName("Buddy");
    dog1.setAge(1);

    Dog dog2 = new Dog();
    dog2.setName("Milo");
    dog2.setAge(2);

    List<Dog> dogs = new ArrayList<>(Arrays.asList(dog1,dog2));

    // Output: 'List dogs: [Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]'
    System.out.println("List dogs: " + dogs);

    // Let's clone and make a deep copy of the dogs' ArrayList:
    List<Dog> clonedDogs = dogs.stream().map(dog -> dog.clone()).collect(Collectors.toList());
    // Output: 'Now list dogs are deep copied into list clonedDogs.'
    System.out.println("Now list dogs are deep copied into list clonedDogs.");

    // A change on dog1 or dog2 can not impact a deep copy.
    // Let's make a change on dog1 and dog2, and test this
    // statement.
    dog1.setName("Bella");
    dog1.setAge(3);
    dog2.setName("Molly");
    dog2.setAge(4);

    // The change is made on list dogs!
    // Output: 'List dogs after change: [Dog{name='Bella', age=3}, Dog{name='Molly', age=4}]'
    System.out.println("List dogs after change: " + dogs);

    // There is no impact on list clonedDogs's inner objects after the deep copy.
    // The deep copy of list clonedDogs was successful!
    // If clonedDogs would be a shallow copy we would see the change on the field
    // "private String name", the change made in list dogs, when setting the names
    // Bella and Molly.
    // Output clonedDogs:
    // 'After change in list dogs, no impact/change in list clonedDogs:\n'
    // '[Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]\n'
    System.out.println("After change in list dogs, no impact/change in list clonedDogs: \n" + clonedDogs);
}

Вывод:

List dogs: [Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]
Now list dogs are deep copied into list clonedDogs.
List dogs after change: [Dog{name='Bella', age=3}, Dog{name='Molly', age=4}]
After change in list dogs, no impact/change in list clonedDogs:
[Dog{name='Buddy', age=1}, Dog{name='Milo', age=2}]

Комментарий. Поскольку после изменения списка собак не происходит никаких изменений / изменений в списке clonedDogs, глубокая копия ArrayList успешна!

Примечание 1. Альтернатива 1 намного медленнее, чем Альтернатива 2, но ее легче поддерживать, поскольку вам не нужно обновлять какие-либо методы, такие как clone ().

Примечание 2: для альтернативы 1 для метода SerializationUtils.clone () использовалась следующая зависимость maven:

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.9</version>
</dependency>

Дополнительные выпуски common-lang3 можно найти по адресу:

https://mvnrepository.com/artifact/org.apache.commons/commons-lang3

person DigitShifter    schedule 18.08.2020

Остальные плакаты верны: вам нужно перебрать список и скопировать в новый список.

Однако ... Если объекты в списке неизменяемы - их не нужно клонировать. Если ваш объект имеет сложный граф объектов - они также должны быть неизменяемыми.

Другое преимущество неизменяемости заключается в том, что они также являются потокобезопасными.

person Fortyrunner    schedule 04.04.2009

Вот решение, использующее общий тип шаблона:

public static <T> List<T> copyList(List<T> source) {
    List<T> dest = new ArrayList<T>();
    for (T item : source) { dest.add(item); }
    return dest;
}
person Andrew Coyte    schedule 20.03.2012
comment
Обобщения - это хорошо, но вам также необходимо клонировать элементы, чтобы ответить на вопрос. См. stackoverflow.com/a/715660/80425 - person David Snabel-Caunt; 21.03.2012

Простой способ, используя commons-lang-2.3.jar, эту библиотеку java для клонирования списка

ссылка загрузить commons-lang-2.3.jar

Как пользоваться

oldList.........
List<YourObject> newList = new ArrayList<YourObject>();
foreach(YourObject obj : oldList){
   newList.add((YourObject)SerializationUtils.clone(obj));
}

Надеюсь, это может вам помочь.

:D

person sonida    schedule 04.04.2013
comment
Просто примечание: почему такая старая версия Commons Lang? См. Историю выпусков здесь: commons.apache.org/proper/commons- lang / release-history.html - person informatik01; 01.05.2013

Пакет import org.apache.commons.lang.SerializationUtils;

Есть способ SerializationUtils.clone(Object);

Пример

this.myObjectCloned = SerializationUtils.clone(this.object);
person pacheco    schedule 02.05.2013
comment
немного устарело отвечать на этот вопрос. И многие другие ответы в комментариях под вопросом. - person moskito-x; 02.05.2013

Я только что разработал библиотеку, которая может клонировать объект сущности и объект java.util.List. Просто загрузите банку в https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U и используйте статический метод cloneListObject (список списка). Этот метод клонирует не только список, но и все элементы сущности.

person Eduardo de Melo    schedule 11.05.2017

Ниже сработало для меня ..

в Dog.java

public Class Dog{

private String a,b;

public Dog(){} //no args constructor

public Dog(Dog d){ // copy constructor
   this.a=d.a;
   this.b=d.b;
}

}

 -------------------------

 private List<Dog> createCopy(List<Dog> dogs) {
 List<Dog> newDogsList= new ArrayList<>();
 if (CollectionUtils.isNotEmpty(dogs)) {
 dogs.stream().forEach(dog-> newDogsList.add((Dog) SerializationUtils.clone(dog)));
 }
 return newDogsList;
 }

Здесь новый список, созданный с помощью метода createCopy, создается с помощью SerializationUtils.clone (). Таким образом, любые изменения, внесенные в новый список, не повлияют на исходный список.

person gayu312    schedule 07.11.2019

Простой способ

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);
person Thanga    schedule 12.08.2020

Думаю, я нашел действительно простой способ сделать полную копию ArrayList. Предполагая, что вы хотите скопировать массив String ArrayList A.

ArrayList<String>arrayB = new ArrayList<String>();
arrayB.addAll(arrayA);

Сообщите мне, если это не сработает для вас.

person jordanrh    schedule 23.11.2016
comment
не работает, если вы используете List ‹List ‹JsonObject›› например в моем случае - person djdance; 14.08.2017
comment
Строки неизменны. Клонирование не имеет смысла, и в вашем примере arrayB и arrayA имеют одинаковые ссылки на объекты - это мелкая копия. - person Christian Fries; 03.08.2018