Come clonare ArrayList e anche clonarne il contenuto?

Come posso clonare un ArrayList e anche clonare i suoi elementi in Java?

Ad esempio ho:

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

E mi aspetterei che gli oggetti in clonedList non siano gli stessi della lista dei cani.

Avrai bisogno di iterare sugli oggetti e clonarli uno per uno, mettendo i cloni nel tuo array di risultati man mano che procedi.

 public static List cloneList(List list) { List clone = new ArrayList(list.size()); for (Dog item : list) clone.add(item.clone()); return clone; } 

Perché ciò funzioni, ovviamente, dovrai ottenere l’object Dog per implementare l’interfaccia Cloneable e il metodo clone ().

Io, personalmente, aggiungerei un costruttore a Dog:

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

Quindi basta ripetere (come mostrato nella risposta di Varkhan):

 public static List cloneList(List dogList) { List clonedList = new ArrayList(dogList.size()); for (Dog dog : dogList) { clonedList.add(new Dog(dog)); } return clonedList; } 

Trovo il vantaggio di questo è che non hai bisogno di girovagare con la roba Cloneable in Java. Corrisponde anche al modo in cui si copiano le raccolte Java.

Un’altra opzione potrebbe essere quella di scrivere la tua interfaccia ICloneable e usarla. In questo modo potresti scrivere un metodo generico per la clonazione.

Tutte le raccolte standard hanno costruttori di copie. Usali.

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

clone() stato progettato con diversi errori (vedi questa domanda ), quindi è meglio evitarlo.

Da efficace Seconda edizione Java , elemento 11: Sostituisci con giudizio il clone

Dati tutti i problemi associati a Cloneable, è sicuro che altre interfacce non dovrebbero estenderlo e che le classi progettate per l’ereditarietà (Articolo 17) non dovrebbero implementarlo. A causa dei suoi numerosi difetti, alcuni programmatori esperti scelgono semplicemente di non sovrascrivere il metodo clone e di non invocarlo mai, tranne, forse, per copiare gli array. Se si progetta una class per ereditarietà, tenere presente che se si sceglie di non fornire un metodo di clonazione protetto ben funzionante, sarà imansible per le sottoclassi implementare Cloneable.

Questo libro descrive anche i numerosi vantaggi che i costruttori di copia hanno su Clonabile / clona.

  • Non si basano su un meccanismo extralinguistico di creazione di oggetti incline alla propensione al rischio
  • Non richiedono un’adesione inapplicabile alle convenzioni scarsamente documentate
  • Non sono in conflitto con l’uso corretto dei campi finali
  • Non lanciano eccezioni controllate non necessarie
  • Non richiedono calchi.

Considera un altro vantaggio dell’uso dei costruttori di copie: supponi di avere un HashSet s e di copiarlo come un TreeSet . Il metodo clone non può offrire questa funzionalità, ma è semplice con un costruttore di conversioni: new TreeSet(s) .

Java 8 fornisce un nuovo modo per chiamare il costruttore di copie o il metodo clone sui cani degli elementi in modo elegante e compatto: stream , lambda e collezionisti .

Copia costruttore:

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

L’espressione Dog::new è chiamata riferimenti al metodo . Fa riferimento a un costruttore di Dog che accetta un altro cane come argomento.

Metodo clone:

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

Ottenere un ArrayList come risultato

Oppure, se devi recuperare una ArrayList (nel caso in cui desideri modificarla in seguito):

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

Aggiorna l’elenco sul posto

Se non è necessario mantenere il contenuto originale dell’elenco dei dogs è ansible utilizzare il metodo replaceAll e aggiornare invece l’elenco in uso:

 dogs.replaceAll(Dog::new); 

Tutti gli esempi presuppongono l’ import static java.util.stream.Collectors.*; .


Collector per ArrayList s

Il collector dell’ultimo esempio può essere trasformato in un metodo util. Dal momento che questa è una cosa così comune, personalmente mi piace che sia breve e carina. Come questo:

 ArrayList clonedDogs = dogs.stream().map(d -> d.clone()).collect(toArrayList()); public static  Collector> toArrayList() { return Collectors.toCollection(ArrayList::new); } 

Nota su CloneNotSupportedException :

Perché questa soluzione funzioni, il metodo clone di Dog non deve dichiarare che genera CloneNotSupportedException . Il motivo è che l’argomento della map non è autorizzato a lanciare eccezioni controllate.

Come questo:

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

Questo comunque non dovrebbe essere un grosso problema, poiché è comunque la migliore pratica. ( Ad esempio Java fornisce questo consiglio).

Grazie a Gustavo per aver notato questo.


PS:

Se lo trovi più carino, puoi utilizzare la syntax del metodo di riferimento per fare esattamente la stessa cosa:

 List clonedDogs = dogs.stream().map(Dog::clone).collect(toList()); 

Fondamentalmente ci sono tre modi senza iterare manualmente,

1 Utilizzo del costruttore

 ArrayList dogs = getDogs(); ArrayList clonedList = new ArrayList(dogs); 

2 Uso di addAll(Collection c)

 ArrayList dogs = getDogs(); ArrayList clonedList = new ArrayList(); clonedList.addAll(dogs); 

3 Usando addAll(int index, Collection c) metodo con parametro int

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

NB: il comportamento di queste operazioni sarà indefinito se la collezione specificata viene modificata mentre l’operazione è in corso.

Penso che la risposta verde corrente sia ctriggers , perché potresti chiedere?

  • Può richiedere di aggiungere molto codice
  • Richiede di elencare tutte le liste da copiare e farlo

Il modo in cui la serializzazione è anche pessima, potresti dover aggiungere Serializable dappertutto.

Quindi qual è la soluzione:

Libreria Java Deep-Cloning La libreria di clonazione è una piccola libreria java open source (apache license) che crea oggetti deep clone. Gli oggetti non devono implementare l’interfaccia Cloneable. Effettivamente, questa libreria può clonare QUALSIASI oggetti java. Può essere utilizzato, ad esempio, nelle implementazioni della cache se non si desidera modificare l’object memorizzato nella cache o quando si desidera creare una copia profonda degli oggetti.

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

Dai un’occhiata su https://github.com/kostaskougios/cloning

Dovrai clonare la ArrayList a mano (eseguendone l’iterazione e copiando ogni elemento in una nuova ArrayList ), perché clone() non lo farà per te. La ragione di ciò è che gli oggetti contenuti in ArrayList potrebbero non implementare Clonable stessi.

Modifica : … e questo è esattamente ciò che fa il codice di Varkhan.

Un modo brutto è farlo con la riflessione. Qualcosa del genere ha funzionato per me.

 public static  List deepCloneList(List original) { if (original == null || original.size() < 1) { return new ArrayList<>(); } try { int originalSize = original.size(); Method cloneMethod = original.get(0).getClass().getDeclaredMethod("clone"); List 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<>(); } } 

Gli altri poster sono corretti: è necessario iterare l’elenco e copiare in un nuovo elenco.

Tuttavia … Se gli oggetti nell’elenco sono immutabili, non è necessario clonarli. Se il tuo object ha un grafo di oggetti complesso, anche loro dovranno essere immutabili.

L’altro vantaggio dell’immutabilità è che sono anche sicuri.

Ecco una soluzione che utilizza un tipo di modello generico:

 public static  List copyList(List source) { List dest = new ArrayList(); for (T item : source) { dest.add(item); } return dest; } 

per te gli oggetti sovrascrivono il metodo 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; } } 

e chiama .clone () per Vector obj o ArraiList obj ….

Modo semplice usando commons-lang-2.3.jar quella libreria di java alla lista cloni

link scarica commons-lang-2.3.jar

Come usare

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

Spero che questo possa essere d’aiuto.

: D

Il pacchetto import org.apache.commons.lang.SerializationUtils;

C’è un metodo SerializationUtils.clone(Object);

Esempio

 this.myObjectCloned = SerializationUtils.clone(this.object); 

Ho appena sviluppato una libreria che è in grado di clonare un object quadro e un object java.util.List. Basta scaricare il jar in https://drive.google.com/open?id=0B69Sui5ah93EUTloSktFUkctN0U e utilizzare il metodo statico cloneListObject (Elenco elenco). Questo metodo non solo clona l’Elenco ma anche tutti gli elementi dell’ quadro.

Ho sempre usato questa opzione:

 ArrayList clonedList = new ArrayList(name_of_arraylist_that_you_need_to_Clone); 

Ho trovato un modo, è ansible utilizzare json per serializzare / unserializzare l’elenco. L’elenco serializzato non contiene alcun riferimento all’object originale quando non è serializzato.

Utilizzando gson:

 List originalList = new ArrayList<>(); // add some items later String listAsJson = gson.toJson(originalList); List newList = new Gson().fromJson(listAsJson, new TypeToken>() {}.getType()); 

Puoi farlo usando jackson e qualsiasi altra libreria json.

Penso di aver trovato un modo davvero semplice per creare una copia profonda di ArrayList. Supponendo che si desideri copiare un array ArrayList di stringhe.

 ArrayListarrayB = new ArrayList(); arrayB.addAll(arrayA); 

Fammi sapere se non funziona per te.