Java-implémenter la copie profonde et superficielle d'un tableau
j'essaie de comprendre le concept de copie superficielle vs profonde En Java. Il y a beaucoup d'articles et de questions et Réponses sur ce sujet, mais chaque fois que j'essaie d'implémenter ces concepts dans un vrai code Java, tout devient flou pour moi.
L'une des réponses sur lesquelles je fonde mon interprétation est dans ce lien , où la copie profonde et superficielle est expliquée par des schémas.
je vais vous montrer ci-dessous mon implémentation pour chaque case:
- "Copie peu profonde:
j'ai pris pour mon exemple la méthode système.arraycopy() comme je l'ai lu dans plusieurs articles qu'il effectue une copie superficielle (avec le clone méthode
public class Test {
public static void main(String[] args) {
NameValue[] instance1 = {
new NameValue("name1", 1),
new NameValue("name2", 2),
new NameValue("name3", 3),
};
NameValue[] instance2 = new NameValue[instance1.length];
// Print initial state
System.out.println("Arrays before shallow copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
// Perform shallow copy
System.arraycopy(instance1, 0, instance2, 0, 3);
// Change instance 1
for (int i = 0; i < 3; i++) {
instance1[i].change();
}
// Print final state
System.out.println("Arrays after shallow copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
}
private static class NameValue {
private String name;
private int value;
public NameValue(String name, int value) {
super();
this.name = name;
this.value = value;
}
public void change() {
this.name = this.name + "-bis";
this.value = this.value + 1;
}
@Override
public String toString() {
return this.name + ": " + this.value;
}
}
}
Le résultat de l'exécution des principales méthodes est comme suit:
Arrays before shallow copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after shallow copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
ce résultat est un conformément au schéma du lien précédent:
- copie en Profondeur:
j'ai pris pour cet exemple la méthode tableaux.copyOf () comme je l'ai lu dans de nombreux articles qu'il effectue une copie profonde (avec les tableaux .copyOfRange method)
public static void main(String[] args) {
NameValue[] instance1 = {
new NameValue("name1", 1),
new NameValue("name2", 2),
new NameValue("name3", 3),
};
NameValue[] instance2 = new NameValue[instance1.length];
// Print initial state
System.out.println("Arrays before deep copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
// Perform deep copy
instance2 = Arrays.copyOf(instance1, 3);
// Change instance 1
for (int i = 0; i < 3; i++) {
instance2[i].change();
}
// Print final state
System.out.println("Arrays after deep copy:");
System.out.println("Instance 1: " + Arrays.toString(instance1));
System.out.println("Instance 2: " + Arrays.toString(instance2));
}
qui affiche:
Arrays before deep copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after deep copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
si nous basons la logique de la copie profonde sur le schéma précédent, cela devrait être le résultat:
Comme vous pouvez le remarquer, le résultat de l'exécution de la méthode main est différente de la logique du schéma ci-dessus.
Toute explication sera la bienvenue.
3 réponses
j'essaie de comprendre le concept de copie superficielle vs profonde En Java.
en Java, vous faites circuler et stockez des références à des objets et non aux objets eux-mêmes.
Ainsi, lorsque vous avez un NameValue[] array
le tableau ne contient pas les objets NameValue
mais des références aux objets.
Donc quand vous faites une copie superficielle à NameValue[] array2
cela signifie que vous copiez juste les références à partir d'un tableau à l'autre. Ce qui signifie effectivement que maintenant les deux array
et array2
se réfèrent exactement aux mêmes objets et tout changement que vous faites de array[2]
sera visible de array2[2]
(même objet).
lorsque vous copiez en profondeur vous copiez chaque objet complètement dans une autre zone de mémoire et vous gardez une référence à ce nouvel objet dans votre nouveau tableau.
De cette façon, les 2 tableaux se réfèrent maintenant à des objets différents et à tout changement array[2]
ne sont pas visibles de array2[2]
mise à jour:
Cela ne s'applique pas aux primitifs qui stockent la valeur réelle et non une référence.
Ainsi, un int[] a
quand vous copiez vous obtenez une copie des valeurs (i.e. copie profonde dans un sens) parce que a[2]
contient la valeur elle-même et non la référence à la valeur.
Je ne sais pas où vous avez lu que copyOf()
effectue une copie profonde, parce que c'est tout simplement faux.
citant javadoc de Arrays.copyOf(T[] original, int newLength)
:
pour tous les indices qui sont valides à la fois dans le tableau original et dans la copie, les deux tableaux contiennent des valeurs identiques .
ça veut dire que c'est une copie superficielle. Pour être une copie profonde, les valeurs devraient indiquer les différents objets, puisque l'objet référencé devrait être une copie.
pour effectuer une copie profonde, vous doivent itérer le tableau et copier les valeurs. Java ne peut pas faire cela pour vous, parce qu'il ne sait pas comment copier l'objet.
E. G. comment Java pourrait-il savoir copier un objet NameValue
? clone()
? Copie du constructeur? Sérialiser+Désérialiser? Méthode de fabrique? D'autres moyens?
je pense qu'il y a un petit malentendu que Arrays.copyOf()
produit une copie profonde.
Arrays.copyOf()
fait un nouveau tableau qui contient de vieilles références à des objets qui ne sont pas copiés et comme le lien que j'ai ajouté explique dans le cas de tableaux imbriqués ils ne seront pas copiés et donc il ne peut pas être considéré comme une deep copie mais une copie superficielle.
voir ce pour plus de renseignements.