Jak sklonować ArrayList, a także klonować jego zawartość?

Jak mogę sklonować ArrayList, a także sklonować jego elementy w Javie?

Na przykład mam:

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

I spodziewałbym się, że obiekty w clonedList nie są takie same jak na liście psów.

Author: Lii, 2009-04-04

17 answers

Będziesz musiał iterować elementy i klonować je jeden po drugim, umieszczając klony w tablicy wyników, gdy idziesz.

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;
}

Aby to zadziałało, oczywiście, będziesz musiał zmusić obiekt psa do zaimplementowania interfejsu i metody clone ().

 172
Author: Varkhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-23 15:46:18

Ja osobiście dodałbym konstruktora do Psa:

class Dog
{
    public Dog()
    { ... } // Regular constructor

    public Dog(Dog dog) {
        // Copy all the fields of Dog.
    }
}

Następnie po prostu iterate (jak pokazano w odpowiedzi Varkhan):

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;
}

Uważam, że zaletą tego jest to, że nie musisz pieprzyć się z zepsutym Cloneable rzeczy w Javie. Pasuje również do sposobu kopiowania kolekcji Java.

Inną opcją może być napisanie własnego interfejsu Iclonable i użycie go. W ten sposób można napisać ogólną metodę klonowania.

 172
Author: cdmckay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-26 13:55:08

Wszystkie standardowe zbiory mają konstruktory kopiujące. Użyj ich.

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

clone() został zaprojektowany z kilkoma błędami (patrz to pytanie ), więc najlepiej go unikać.

From Effective Java 2nd Edition , poz. 11: Override clone

Biorąc pod uwagę wszystkie problemy związane z Cloneable, można śmiało powiedzieć że inne Interfejsy nie powinny go rozszerzać, a klasy przeznaczony do dziedziczenia (poz. 17) nie powinien realizować to. Na jego wiele wad, niektórzy programiści ekspertów po prostu wybrać nigdy nie nadpisać metodę klonowania i nigdy jej nie wywoływać z wyjątkiem, być może, skopiuj tablice. Jeśli projektujesz klasę do dziedziczenia, pamiętaj, że jeśli zdecydujesz się nie dostarczać dobrze zachowywanej metody klonowania chronionego, to nie będzie możliwe, aby podklasy zaimplementowały Cloneable.

Ta książka opisuje również wiele zalet konstruktorów kopii nad Cloneable/clone.

  • oni nie polegaj na ryzykownym pozalingwistycznym tworzeniu obiektów mechanizm
  • Nie domagają się nieegzekwowalnego przestrzegania słabo udokumentowanych konwencji.]}
  • nie kolidują z prawidłowym użyciem pól końcowych
  • nie rzucają niepotrzebnych sprawdzonych WYJĄTKÓW
  • Nie wymagają odlewów.

Rozważ inną korzyść z używania konstruktorów kopiujących: Załóżmy, że masz HashSet s i chcesz skopiować ją jako TreeSet. Metoda klonowania nie może oferować tej funkcjonalności, ale jest to łatwe z konstruktorem konwersji: new TreeSet(s).

 124
Author: Rose Perrone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:39

Java 8 udostępnia nowy sposób na eleganckie i kompaktowe wywołanie konstruktora kopiującego lub metody klonowania na elemencie: strumienie, lambda i kolektory.

Konstruktor kopii:

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

Wyrażenie Dog::new nazywa się referencją metody . Tworzy obiekty funkcyjne, które wywołują konstruktor na Dog, który przyjmuje innego psa jako argument.

Klon metoda:

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

Otrzymanie ArrayList jako wyniku

W przypadku, gdy chcesz później zmodyfikować plik, musisz go odzyskać (w przypadku, gdy chcesz go później zmodyfikować):
ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));

Zaktualizuj listę na miejscu

Jeśli nie musisz zachować oryginalnej zawartości listy dogs, możesz użyć metody replaceAll i zamiast tego zaktualizować listę:

dogs.replaceAll(Dog::new);

Wszystkie przykłady zakładają import static java.util.stream.Collectors.*;.


Kolektor dla ArrayLists

The collector from the last przykład można przekształcić w metodę util. Ponieważ jest to taka powszechna rzecz, osobiście lubię, aby była krótka i ładna. Tak:

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

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

Uwaga na CloneNotSupportedException:

Aby To rozwiązanie działało clone metoda Dog nie może oświadczać, że rzuca CloneNotSupportedException. Powodem jest to, że argument map nie może wyrzucać żadnych sprawdzonych WYJĄTKÓW.

Tak:

    // Note: Method is public and returns Dog, not Object
    @Override
    public Dog clone() /* Note: No throws clause here */ { ...

Nie powinno to być jednak dużym problemem, ponieważ jest to najlepszy i tak ćwicz. (Effectice Java na przykład daje tę radę.)

Dzięki Gustavo za Zauważenie tego.


PS:

Jeśli uważasz, że jest ładniejsza, możesz zamiast tego użyć składni referencji metody, aby zrobić dokładnie to samo:

List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
 32
Author: Lii,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-20 19:47:28

Zasadniczo są trzy sposoby bez iterowania ręcznie,

1 Użycie konstruktora

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>(dogs);

2 Using addAll(Collection<? extends E> c)

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(dogs);

3 używając metody addAll(int index, Collection<? extends E> c) z parametrem int

ArrayList<Dog> dogs = getDogs();
ArrayList<Dog> clonedList = new ArrayList<Dog>();
clonedList.addAll(0, dogs);

NB: zachowanie tych operacji będzie niezdefiniowane, jeśli określona kolekcja zostanie zmodyfikowana podczas trwania operacji.

 26
Author: javatar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-29 15:41:25

Myślę, że obecna Zielona odpowiedź jest zła , Dlaczego można zapytać?

  • może wymagać dodania dużej ilości kodu
  • to wymaga, aby wymienić wszystkie listy do skopiowania i zrobić to

Sposób serializacji jest również zły imo, być może będziesz musiał dodać Serializable wszędzie.

Więc jakie jest rozwiązanie:

Biblioteka głębokiego klonowania Javy biblioteka klonowania jest małą biblioteką Javy o otwartym kodzie źródłowym (Licencja apache), która głęboko klonuje obiektów. Obiekty nie muszą implementować interfejsu do klonowania. Efektywnie ta biblioteka może klonować dowolne obiekty java. Może być stosowany np. w implementacjach pamięci podręcznej, jeśli nie chcesz, aby buforowany obiekt był modyfikowany lub gdy chcesz utworzyć głęboką kopię obiektów.

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

Sprawdź na https://github.com/kostaskougios/cloning

 18
Author: Cojones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-05 05:18:28

Będziesz musiał sklonować ArrayList ręcznie (przez iterację nad nim i skopiowanie każdego elementu do nowego ArrayList), ponieważ clone() nie zrobi tego za Ciebie. Powodem tego jest to, że obiekty zawarte w ArrayList mogą nie implementować Clonable same.

Edit:... i właśnie to robi Kodeks Varkhana.

 2
Author: Stephan202,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-17 15:43:25

Paskudnym sposobem jest zrobienie tego z refleksją. Coś takiego działa na mnie.

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<>();
    }
}
 1
Author: milosmns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-01 20:59:54

Pozostałe plakaty są poprawne: musisz iterować listę i skopiować do nowej listy.

Jednak... Jeśli obiekty na liście są niezmienne - nie musisz ich klonować. Jeśli twój obiekt ma złożony Wykres obiektów - będą one również musiały być niezmienne.

Inną zaletą niezmienności jest to, że są one również bezpieczne.

 0
Author: Fortyrunner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-04 10:12:21

Oto rozwiązanie wykorzystujące ogólny typ szablonu:

public static <T> List<T> copyList(List<T> source) {
    List<T> dest = new ArrayList<T>();
    for (T item : source) { dest.add(item); }
    return dest;
}
 0
Author: Andrew Coyte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-20 23:31:25

For you objects override Clone () method

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;
    }
}
I zadzwoń .clone() dla wektora obj lub ArraiList obj....
 0
Author: RN3KK Nick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-10 13:51:29

Łatwy sposób używając commons-lang-2.3.jar that library of java to clone list

Link Pobierz commons-lang-2.3.jar

Jak używać

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

Mam nadzieję, że ten może pomóc.

: D

 0
Author: sonida,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-04 16:20:19

Pakiet import org.apache.commons.lang.SerializationUtils;

Istnieje metoda SerializationUtils.clone(Object);

Przykład

this.myObjectCloned = SerializationUtils.clone(this.object);
 0
Author: pacheco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-02 20:31:43

Właśnie opracowałem lib, który jest w stanie sklonować obiekt encji i Javę.util.Lista obiektów. Wystarczy pobrać jar w https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U i użyć statycznej metody cloneListObject (List list). Ta metoda nie tylko klonuje listę, ale także wszystkie elementy encji.

 0
Author: Eduardo de Melo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-11 23:28:53

Używałem tej opcji zawsze:

ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
 0
Author: besartm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-18 07:20:16

Znalazłem sposób, możesz użyć json do serializacji / unserializacji listy. Lista serializowana nie zawiera odniesienia do oryginalnego obiektu, gdy jest niezerializowana.

Using 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());

Możesz to zrobić używając Jacksona i każdej innej biblioteki json.

 -1
Author: sagits,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-09 21:44:16

Myślę, że znalazłem naprawdę łatwy sposób na zrobienie głębokiej kopii ArrayList. Zakładając, że chcesz skopiować Łańcuch ArrayList arrayA.

ArrayList<String>arrayB = new ArrayList<String>();
arrayB.addAll(arrayA);
Daj mi znać, jeśli ci to nie pomoże.
 -1
Author: jordanrh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-23 22:43:09