Duplicata possible:
Java: comment cloner ArrayList mais aussi cloner ses éléments?
J'ai un exemple de programme comme le suivant:
ArrayList<Invoice> orginalInvoice = new ArrayList<Invoice>();
//add some items into it here
ArrayList<Invoice> copiedInvoice = new ArrayList<Invoice>();
copiedInvoice.addAll(orginalInvoice);
Je pensais pouvoir modifier des éléments à l'intérieur de copiedInvoice
et cela n'affecterait pas ces éléments à l'intérieur de originalInoice
. Mais je me trompais.
Comment puis-je faire une copie/un clone séparé d'un ArrayList
?
Merci
Oui c'est correct - Vous devez implémenter clone()
(ou un autre mécanisme approprié pour copier votre objet, car clone()
est considéré comme "cassé" par de nombreux programmeurs). Votre méthode clone()
doit effectuer une copie complète de tous les champs modifiables de votre objet. De cette façon, les modifications apportées à l'objet cloné n'affecteront pas l'original.
Dans votre exemple de code, vous créez un second ArrayList
et le remplissez avec références aux mêmes objets, c'est pourquoi les modifications apportées à l'objet sont visibles des deux List
s. Avec l'approche clone, votre code ressemblerait à:
List<Foo> originalList = ...;
// Create new List with same capacity as original (for efficiency).
List<Foo> copy = new ArrayList<Foo>(originalList.size());
for (Foo foo: originalList) {
copy.add((Foo)foo.clone());
}
MODIFIER : Pour clarifier, le code ci-dessus effectue une copie complète de l'original List
par lequel le nouveau List
contient des références à des copies des objets originaux. Cela contraste avec l'appel de ArrayList.clone()
, qui effectue un shallow copy
Du List
. Dans ce contexte, une copie superficielle crée une nouvelle instance List
mais contenant des références aux objets d'origine.
Si vous stockez des objets modifiables dans la liste de tableaux, vous devrez copier chaque objet lorsque vous copiez la liste de tableaux. Sinon, la nouvelle ArrayList contiendra toujours les références d'origine.
Cependant, si vous stockez des objets immuables, il est bon d'utiliser:
ArrayList copiedInvoice = new ArrayList(originalInvoice);
Je pensais que je pouvais modifier des éléments à l'intérieur de la copie de la facture et cela n'affecterait pas ces éléments à l'intérieur de la facture d'origine.
Cela se produit car ce qui est copié est la variable de référence et non l'objet lui-même.
Vous vous retrouvez donc avec deux "références" pointant vers le même objet.
Si vous devez copier l'intégralité de l'objet, vous devrez peut-être le cloner.
Mais vous pourriez avoir des problèmes si vous ne clonez pas les attributs internes de l'objet s'ils se trouvent être d'autres objets.
Par exemple, la définition de classe suivante ne vous posera aucun problème.
public class Something {
private int x;
private int y;
private String stringObject;
}
Si vous créez une copie de cela, vous copiez les valeurs actuelles de ses attributs et c'est tout.
Mais si votre classe contient un autre objet à l'intérieur, vous pouvez également envisager de le cloner.
class OtherSomething {
Something something;
private int x;
}
Si vous procédez comme suit:
Something shared = new Something();
OtherSomething one = new OtherSomething();
OtherSomething two = new OtherSomething();
one.something = shared;
two.something = shared;
Dans ce cas, un et deux ont la même variable de référence pour le même "quelque chose" partagé et changer la valeur dans l'un affecterait l'autre.
C'est pourquoi il est beaucoup plus simple/meilleur/plus facile d'utiliser des objets immuables.
Si vous devez modifier la valeur d'un objet immuable, vous devez simplement en créer un nouveau avec la valeur correcte.