Как клонировать 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.*;.


коллектор 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), которая глубоко клонирует объекты. Объекты не должны реализовывать интерфейс 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);

Дайте мне знать, если это не сработает для вас.