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.
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 ().
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.
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)
.
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());
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.
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
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.
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<>();
}
}
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.
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;
}
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....
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
le colis import org.apache.commons.lang.SerializationUtils;
il y a une méthode SerializationUtils.clone(Object);
exemple
this.myObjectCloned = SerializationUtils.clone(this.object);
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.
j'ai toujours utilisé cette option:
ArrayList<Dog> clonedList = new ArrayList<Dog>(name_of_arraylist_that_you_need_to_Clone);
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.
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.