En Java, qu’est-ce qu’une copie superficielle?

java.util.Calendar.clone () renvoie “… un nouveau calendrier avec les mêmes propriétés” et renvoie “une copie superficielle de ce calendrier”.

Cela ne semble pas être une copie superficielle comme répondu ici sur SO. Cette question est balisée par la langue, Java ne semble pas suivre la définition agnostique du langage. En parcourant le code, je remarque que la structure et les éléments sont copiés sur ce nouvel object, plus que la structure agnostique du langage uniquement.

En Java, qu’est-ce qu’une copie superficielle?

En quoi diffère-t-il d’une copie profonde Java (si elle existe)?

Une copie superficielle copie simplement les valeurs des références dans la classe. Une copie en profondeur copie les valeurs. donné:

class Foo { private Bar myBar; ... public Foo shallowCopy() { Foo newFoo = new Foo(); newFoo.myBar = myBar; return newFoo; } public Foo deepCopy() { Foo newFoo = new Foo(); newFoo.myBar = myBar.clone(); //or new Bar(myBar) or myBar.deepCopy or ... return newFoo; } } Foo myFoo = new Foo(); Foo sFoo = myFoo.shallowCopy(); Foo dFoo = myFoo.deepCopy(); myFoo.myBar == sFoo.myBar => true myFoo.myBar.equals(sFoo.myBar) => true myFoo.myBar == dFoo.myBar => **false** myFoo.myBar.equals(dFoo.myBar) => true 

Dans ce cas, la copie superficielle a la même référence ( == ) et la copie profonde a uniquement une référence équivalente ( .equals() ).

Si une modification est apscope à la valeur d’une référence peu copiée, la copie reflète ce changement car elle partage la même référence. Si une modification est apscope à la valeur d’une référence profondément copiée, la copie ne reflète pas ce changement car elle ne partage pas la même référence.

C-ism

 int a = 10; //init int& b = a; //shallow - copies REFERENCE int c = a; //deep - copies VALUE ++a; 

Résultat:

 a is 11 *b is 11 c is 10 

La copie superficielle est juste un ensemble de pointeurs vers les mêmes emplacements de mémoire. En fait, il ne crée pas de copie réelle, ce qui réduit l’utilisation de la mémoire.

Dans le cas d’une copie profonde, une copie exacte du segment de mémoire est créée et les pointeurs sont définis sur de nouveaux emplacements de mémoire. Donc théoriquement, la consommation de mémoire devrait être deux fois plus importante dans ce cas.

Une copie superficielle est une copie du pointeur de référence sur l’object, tandis qu’une copie profonde est une copie de l’object lui-même. En Java, les objects sont conservés en arrière-plan, ce à quoi vous interagissez normalement lorsque vous traitez les objects, ce sont les pointeurs. Les noms de variables pointent vers l’espace mémoire de l’object. Une copie superficielle est faite lorsque vous définissez une variable égale à une autre comme suit:

 Object B = A; 

Une copie en profondeur peut être faite en obtenant les propriétés de l’object A et en les plaçant dans un nouvel object B.

 Object B = new Object(A.getProperty1(), A.getProperty2()...); 

Cela affecte le comportement du programme en ce sens que si vous faites une copie superficielle et effectuez une tâche dessus, cela affecte toutes les copies peu profondes de l’object. Si vous modifiez une copie profonde, seule cette copie est affectée. J’espère que c’est assez détaillé pour vous.

Le document docs 1.6 indique Calendar.clone comme “Crée et retourne une copie de cet object”. Une copie superficielle littérale telle que spécifiée par Object.clone n’aurait aucun sens. Java utilise le terme “copie superficielle” dans un sens assez typique.

Cela semble être une erreur dans la documentation. Je ne vois pas comment quoi que la méthode Calendar.clone d’Android réponde à la définition typique (en Java ou autre) d’une “copie superficielle”.

Où trouvez-vous cette documentation?

Les documents officiels de Java 6 sur java.sun.com ont simplement Calendar.clone () renvoyant une copie de l’object. Aucune mention de superficiel.

Plus généralement, une copie superficielle en Java est une copie de référence d’object, mais le nouvel object contient (directement ou indirectement) des références aux données de l’original.

Par exemple:

 class MyClass{ private List innerList; public MyClass(List list) { innerList = list; } //Some code... public Object clone(){ return new MyClass(innerList); } } 

renvoie une copie superficielle dans son clone ().

Tout d’abord, le Javadoc de ArrayList est quelque peu faux si nous parlons de tableaux à une dimension, car il utilise la méthode copyOf dans Arrays. Donc, clone () renvoie une copie unidimensionnelle, du moins depuis 1.5 (je n’ai pas testé plus loin)! C’est ce que signifie “peu profonde” en Java: unidimensionnel

Vous pouvez en lire plus ici: http://www.javapractices.com/topic/TopicAction.do?Id=3 . Donc, clone () n’est pas une copie superficielle! Si vous voulez une vraie copie superficielle d’un tableau à une dimension, faites-en simplement référence:

 Array a = new Array(); Array b = a; //a is only a shallow copy, nice for synchronisation 

Les tableaux en Java sont délicats, car Java ne les transmet pas, mais les valeurs des tableaux ne sont que leurs pointeurs! D’autre part, cela nous permet de synchroniser les objects, ce qui est une excellente chose. Cependant, il existe certains problèmes si vous utilisez des tableaux dans des tableaux (ou ArrayLists), car un clone () du tableau de conteneurs (ou ArrayList) ne copiera pas leurs valeurs, mais uniquement leurs références! Donc, vous ne devriez simplement pas mettre de tableaux dans un tableau, vous ne devriez traiter que des objects dans un tableau!

Et Javadoc est difficile à comprendre parfois, alors testez-le …

S’amuser!

Une copie superficielle copie simplement la référence de l’object dans la référence cible. Il ne crée pas un nouvel object sur le tas. Par défaut, Java effectue un clonage superficiel en utilisant la fonction clone ().

Pour obtenir un nouvel object sur le tas, il faut effectuer un clonage profond qui peut être implémenté par sérialisation et désérialisation.

Dans une copie superficielle, l’object clone possède une copie des valeurs primitives, mais les références aux objects font référence aux mêmes objects que la copie d’origine. Les copies superficielles ont un inconvénient important, l’object cloné et la copie d’origine font référence au même object d’adresse. Toute modification apscope par l’object cloné dans l’object d’adresse sera également reflétée dans la copie d’origine, ce qui constitue un comportement indésirable. Ce que nous voulions vraiment, ce sont deux copies distinctes de l’object utilisateur. La copie profonde vient à notre secours pour ce genre de situation.

La copie en profondeur des clones, pas seulement les valeurs primitives, crée également des copies des références des objects.

Vous pouvez consulter un exemple de travail à ce sujet ici: https://codingninjaonline.com/2017/11/09/deep-vs-shallow-copy/