Comment cloner ArrayList et aussi cloner son contenu?

Comment puis-je cloner un ArrayList et aussi ses articles en Java?

par exemple j'ai:

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

et je m'attendrais à ce que les objets dans clonedList ne sont pas les mêmes que dans la liste des chiens.

230
demandé sur Lii 2009-04-04 00:40:28

17 réponses

vous aurez besoin d'itérer sur les éléments, et de les cloner un par un, en mettant les clones dans votre tableau de résultats que vous allez.

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

pour que cela fonctionne, évidemment, vous devrez obtenir votre objet Dog pour implémenter l'interface clonable, et la méthode clone ().

172
répondu Varkhan 2016-08-23 15:46:18

personnellement, j'ajouterais un constructeur à Dog:

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

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

puis il suffit d'itérer (comme indiqué dans la réponse de 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;
}

je trouve que l'avantage de ceci est que vous n'avez pas besoin de déconner avec la substance brisée clonable en Java. Il correspond également à la façon dont vous copiez les collections Java.

une autre option pourrait être d'écrire votre propre interface ICloneable et de l'utiliser. De cette façon, vous pourriez écrire un générique méthode de clonage.

172
répondu cdmckay 2011-05-26 13:55:08

toutes les collections standard ont des constructeurs de copies. Les utiliser.

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

clone() a été conçu avec plusieurs erreurs (voir cette question ), il est donc préférable de l'éviter.

à Partir de Effective Java 2nd Edition , Article 11: Remplacer clone judicieusement

compte tenu de tous les problèmes associés à Clonable, il est sûr de dire autres interfaces ne devrait pas s'étendre, et que les classes conçu pour l'héritage (Point 17) ne devrait pas le mettre en œuvre. En raison de ses nombreuses lacunes, certains programmeurs experts choisissent simplement de ne jamais outrepasser la méthode du clone et ne jamais l'invoquer sauf, peut-être, à copier des tableaux. Si vous créez une classe pour l'héritage, sachez que si vous choisissez de ne pas fournir une sage protégé méthode clone, il il sera impossible pour les sous-classes de mettre en œuvre clonable.

ce livre décrit également les nombreux avantages que les constructeurs de copie ont par rapport à clonable/clone.

  • ils ne s'appuient pas sur une création extralinguistique risquée mécanisme
  • qu'Ils n'exigent pas inapplicable adhésion à finement documenté conventions
  • Ils n'entrent pas en conflit avec la bonne utilisation de finale champs
  • ils ne jettent pas les exceptions vérifiées inutiles
  • ils n'ont pas besoin de moulage.

considérez un autre avantage d'utiliser des constructeurs de copie: supposons que vous ayez un HashSet s , et que vous voulez le copier comme un TreeSet . La méthode clone ne peut pas offrir cette fonctionnalité, mais c'est facile avec un constructeur de conversion: new TreeSet(s) .

124
répondu Rose Perrone 2017-05-23 12:02:39

Java 8 fournit une nouvelle façon d'appeler le constructeur de copie ou la méthode de clone sur les chiens d'élément avec élégance et compacité: Streams , lambdas et collectors .

constructeur de Copie:

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

l'expression Dog::new est appelée référence de méthode . Il crée un fonction objects qui appelle un constructeur sur Dog qui prend un autre chien comme argument.

méthode Clone:

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

obtenir un ArrayList comme le résultat

Ou, si vous devez obtenir un ArrayList à l'arrière (dans le cas où vous souhaitez le modifier plus tard):

ArrayList<Dog> clonedDogs = dogs.stream().map(Dog::new).collect(toCollection(ArrayList::new));

mettre à jour la liste en place

si vous n'avez pas besoin de conserver le contenu original de la liste dogs , vous pouvez utiliser la méthode replaceAll et mettre à jour la liste à la place:

dogs.replaceAll(Dog::new);

tous les exemples supposent import static java.util.stream.Collectors.*; .


Collecteur ArrayList s

le collecteur du dernier exemple peut être transformé en une méthode util. Car c'est d'un commun chose à faire j'aime personnellement qu'il soit court et joli. Comme ceci:

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

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

Note sur CloneNotSupportedException :

pour que cette solution fonctionne la clone méthode de Dog ne doit pas déclarer qu'il jette CloneNotSupportedException . La raison est que l'argument à map n'est pas autorisé à jeter toutes les exceptions vérifiées.

comme ceci:

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

cela ne devrait pas être un gros problème, car c'est de toute façon la meilleure pratique. ( Effectice Java par exemple donne ce conseil.)

merci à Gustavo d'avoir noté cela.


PS:

si vous le trouvez plus joli, vous pouvez utiliser la syntaxe de référence de la méthode pour faire exactement la même chose.:

List<Dog> clonedDogs = dogs.stream().map(Dog::clone).collect(toList());
32
répondu Lii 2018-09-20 19:47:28

fondamentalement, il y a trois façons sans itération manuelle,
151980920

1 utilisant le constructeur

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

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

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

3 utilisant addAll(int index, Collection<? extends E> c) méthode avec int paramètre

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

NB: le comportement de ces opérations ne sera pas défini si la collection spécifiée est modifiée pendant que l'opération est en cours.

26
répondu javatar 2016-07-29 15:41:25

je pense que le courant vert réponse est mauvaise , pourquoi me demanderez-vous?

  • Elle peut nécessiter d'ajouter une grande quantité de code
  • il vous demande d'énumérer toutes les listes à copier et de le faire

la façon serialization est aussi mauvais imo, vous pourriez avoir à ajouter Serialisable partout dans l'endroit.

alors quelle est la solution:

Java Profonde-Clonage de la bibliothèque Le clonage de la bibliothèque est un petit open source (licence apache) bibliothèque java qui profonde clones objets. Les objets n'ont pas à implémenter l'interface clonable. Effectivement, cette bibliothèque peut cloner N'importe quel objet java. Il peut être utilisé dans les implémentations de cache si vous ne voulez pas que l'objet mis en cache soit modifié ou chaque fois que vous voulez créer une copie profonde d'objets.

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

Check it out at https://github.com/kostaskougios/cloning

18
répondu Cojones 2017-03-05 05:18:28

vous aurez besoin de cloner le ArrayList à la main (en itérant dessus et en copiant chaque élément à un nouveau ArrayList ), parce que clone() ne le fera pas pour vous. La raison en est que les objets contenus dans le ArrayList ne peuvent pas implémenter Clonable eux-mêmes.

Modifier : ... et c'est exactement ce que fait le code de Varkhan.

2
répondu Stephan202 2016-03-17 15:43:25

une mauvaise façon est de le faire avec réflexion. Quelque chose comme ça a marché pour moi.

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
répondu milosmns 2015-10-01 20:59:54

les autres posters sont corrects: vous devez itérer la liste et copier dans une nouvelle liste.

cependant... Si les objets de la liste sont immuables - vous n'avez pas besoin de les cloner. Si votre objet est un objet complexe graphique - ils auront besoin d'être immuable.

L'autre avantage de l'immuabilité, c'est qu'ils sont thread-safe.

0
répondu Fortyrunner 2009-04-04 10:12:21

Voici une solution utilisant un modèle générique:

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
répondu Andrew Coyte 2012-03-20 23:31:25

pour vous des objets de remplacer méthode 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;
    }
}

et appelez .clone () pour obj vecteur ou OBJ ArraiList....

0
répondu RN3KK Nick 2012-09-10 13:51:29

voie Facile en utilisant commons-lang-2.3.jar que la bibliothèque de java pour cloner liste

lien télécharger commons-lang-2.3.jar

comment utiliser

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

j'espère que celui-ci peut aider.

: d

0
répondu sonida 2013-04-04 16:20:19

le colis import org.apache.commons.lang.SerializationUtils;

il y a une méthode SerializationUtils.clone(Object);

exemple

this.myObjectCloned = SerializationUtils.clone(this.object);
0
répondu pacheco 2013-05-02 20:31:43

je viens de développer un lib capable de cloner un objet entity et un java.util.Des objets de la liste. Il suffit de télécharger le pot dans https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U et utiliser la méthode statique cloneListObject(liste). Cette méthode Clone non seulement la liste mais aussi tous les éléments d'entity.

0
répondu Eduardo de Melo 2017-05-11 23:28:53

j'ai toujours utilisé cette option:

ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
0
répondu besartm 2018-05-18 07:20:16

j'ai trouvé un moyen, vous pouvez utiliser json pour sérialiser/désérialiser la liste. Le sérialisé liste contient aucune référence à l'objet d'origine lors de la désérialisation.

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

vous pouvez faire cela en utilisant jackson et n'importe quelle autre bibliothèque json aussi.

-1
répondu sagits 2016-06-09 21:44:16

je pense que j'ai trouvé un moyen vraiment facile de faire une copie ArrayList profonde. En supposant que vous voulez copier une chaîne ArrayList arrayA.

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

dites-moi si ça ne marche pas pour vous.

-1
répondu jordanrh 2016-11-23 22:43:09