2008-09-10 6 views
129

J'ai un ArrayList<String> que je voudrais retourner une copie de. ArrayList a une méthode clone a la signature suivante:Comment cloner une liste générique en Java?

public Object clone() 

Après avoir appelé cette méthode, comment puis-je jetai le dos objet retourné à ArrayList<String>?

+14

Non, cela est une question valide. Java ne supporte pas les "vrais" génériques, avec effacement de type à l'exécution et tout, donc ces types de détails peuvent être difficiles. En outre, l'interface Cloneable et le mécanisme de la méthode Object.clone() sont également source de confusion. –

+0

OK, je fais surtout du C# où c'est vraiment facile. S'il vous plaît laissez-moi savoir si vous voulez que je supprime les commentaires de cette question. – Espo

+1

Vous pouvez laisser le commentaire. Je pense que mes modifications ont expliqué ce que j'avais des problèmes avec. –

Répondre

50
ArrayList newArrayList = (ArrayList) oldArrayList.clone(); 
+35

Cela fonctionne très bien pour Strings (ce qui est la question demandée), mais il est à noter que ArrayList.clone effectuera une copie superficielle, donc s'il y avait des objets mutables dans la liste, ils ne seront pas clonés (et changeant Une liste en une va également changer celle-ci dans l'autre liste – pkaeding

+43

Vous devriez éviter d'utiliser des types bruts dans n'importe quel code sauf le code hérité: il vaut mieux utiliser 'ArrayList newArrayList = (ArrayList ) oldArrayList.clone();' – cdmckay

+18

Dommage, ArrayList a une méthode #clone, mais List lui-même ne le fait pas.Sigh – rogerdpack

1
ArrayList first = new ArrayList(); 
ArrayList copy = (ArrayList) first.clone(); 
5

Je trouve l'aide addAll fonctionne très bien.

ArrayList(String) copy = new ArrayList(String)(); 
copy.addAll(original); 

entre parenthèses sont utilisées plutôt que la syntaxe des génériques

+4

Cela fonctionnera pour les chaînes, mais pas pour les objets modifiables. Vous aurez envie de les cloner aussi. – jodonnell

+0

Ouais, sa question est pour les cordes. Et il a le problème des génériques qui n'aiment pas vraiment les trucs de casting dans ce cas. –

+0

En outre, ArrayList.clone ne fera qu'un clone superficiel, donc les objets mutables dans la liste ne seront pas clonés en utilisant cette méthode non plus. – pkaeding

2

Cela devrait aussi fonctionner:

ArrayList<String> orig = new ArrayList<String>(); 
ArrayList<String> copy = (ArrayList<String>) orig.clone() 
+1

Cela ne fonctionnera pas car List n'a pas de méthode clone. –

+0

En effet.Je viens de le mettre à jour pour résoudre ce problème. – pkaeding

+9

Eh bien, maintenant mon commentaire semble juste stupide. :) –

14

Je pense que cela devrait faire l'affaire en utilisant l'API Collections:

Remarque : la méthode de copie s'exécute en temps linéaire.

//assume oldList exists and has data in it. 
List<String> newList = new ArrayList<String>(); 
Collections.copy(newList, oldList); 
+13

Pourquoi ne pas simplement utiliser le nouveau ArrayList (oldList)? – cdmckay

+3

Je crois que cela ne fonctionnerait pas, à partir de doc * La liste de destination doit être au moins aussi longue que la liste des sources. Si elle est plus longue, les éléments restants dans la liste de destination ne sont pas affectés. –

+0

@GregDomjan pas que je suis d'accord que c'est la meilleure façon, mais c'est une façon de le faire. Pour contourner votre problème c'est aussi simple que ceci: Liste newList = new ArrayList <> (oldList.size()); – nckbrz

276

Pourquoi voudriez-vous cloner? Créer une nouvelle liste a généralement plus de sens.

List<String> strs; 
... 
List<String> newStrs = new ArrayList<>(strs); 

Travail effectué.

+16

Vous ne pouvez pas savoir de quel type de liste il s'agit. Il peut s'agir d'une LinkedList, d'une MyOwnCustomList ou d'une sous-classe de ArrayList, auquel cas la création d'une ArrayList serait de type incorrect. –

+48

Serais-je intéressé par la mise en œuvre de la liste d'origine? Je me soucie probablement de la mise en œuvre que la nouvelle liste utilise. –

+12

@Steve Kuo: La signature est 'ArrayList (Collection c)' ce qui signifie que peu importe le type de liste que vous utilisez comme argument. – cdmckay

16

Soyez avisé que Object.clone() a quelques problèmes majeurs, et son utilisation est déconseillée dans la plupart des cas. S'il vous plaît voir le point 11, de "Effective Java" par Joshua Bloch pour une réponse complète. Je crois que vous pouvez utiliser Object.clone() en toute sécurité sur des tableaux de types primitifs, mais en dehors de cela, vous devez être judicieux pour utiliser et écraser correctement un clone. Il est probablement préférable de définir un constructeur de copie ou une méthode d'usine statique qui clone explicitement l'objet en fonction de votre sémantique.

2

Faites très attention lorsque vous clonez ArrayLists. Le clonage en Java est peu profond. Cela signifie qu'il ne fera que cloner l'Arraylist lui-même et non ses membres. Donc, si vous avez une ArrayList X1 et la clonez dans X2, toute modification de X2 se manifestera également dans X1 et vice-versa. Lorsque vous clonez, vous générez uniquement une nouvelle ArrayList avec des pointeurs vers les mêmes éléments dans l'original.

0

Je ne suis pas un professionnel Java, mais j'ai le même problème et j'ai essayé de résoudre par cette méthode. (Il suppose que T a un constructeur de copie).

public static <T extends Object> List<T> clone(List<T> list) { 
     try { 
      List<T> c = list.getClass().newInstance(); 
      for(T t: list) { 
      T copy = (T) t.getClass().getDeclaredConstructor(t.getclass()).newInstance(t); 
      c.add(copy); 
      } 
      return c; 
     } catch(Exception e) { 
      throw new RuntimeException("List cloning unsupported",e); 
     } 
} 
20

C'est le code que j'utilise pour cela:

ArrayList copy = new ArrayList (original.size()); 
Collections.copy(copy, original); 

L'espoir est utile pour vous

+1

Et évitez d'utiliser des types bruts .. donc au lieu de 'ArrayList' utilisez' ArrayList ' – milosmns

+1

http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#copy-java. util.List-java.util.List- Ne fonctionne pas car les tailles de liste sont différentes. –

2

Ma fonction de cloner une liste avec le type:

public static <T extends Object> List<T> cloneList(List<T> list) { 
    return ((List<T>) ((ArrayList<T>) list).clone()); 
} 
+0

Vous lancez une liste inconnue dans ArrayList, ce qui ne fonctionnera pas s'il n'en était pas un. –

2

Pour clone une interface générique comme java.util.List vous aurez juste besoin de le lancer.Vous êtes un exemple:

List list = new ArrayList(); 
List list2 = ((List) ((ArrayList) list).clone()); 

Il est un peu délicat, mais il fonctionne, si vous êtes limité à retourner une interface List, donc tout le monde après que vous pouvez mettre en œuvre votre liste chaque fois qu'il veut.

Je sais que cette réponse est proche de la réponse finale, mais ma réponse me répond comment faire tout cela pendant que vous travaillez avec List -le parent- générique ne ArrayList

+1

vous supposez que ce sera toujours un ArrayList qui n'est pas vrai –

+0

@JuanCarlosDiaz va, c'est la question posée, il s'agissait de ArrayList, donc j'ai répondu pour ArrayList :) –

12

Avec Java 8, il peut être clonées avec un courant.

import static java.util.stream.Collectors.toList; 

...

List<AnObject> clone = myList.stream().collect(toList()); 
4

Si vous voulez ceci afin de pouvoir retourner la liste dans un getter il serait préférable de le faire:

ImmutableList.copyOf(list); 
Questions connexes