t
t
t
t
t t   A) Passage et Retour d'Objets
tttt
t
carrea) Préface carreb) Avant-propos carre1) Introduction sur les &laqo; objets » carre2) Tout est &laqo; objet » carre3) Contrôle du flux du programme carre4) Initialization & Cleanup carre5) Cacher l'implémentation carre6) Réutiliser les classes carre7) Polymorphisme carre8) Interfaces & classes internes carre9) Stockage des objets carre10) Error Handling with Exceptions carre11) Le système d’E/S de Java carre12) Identification dynamique de type carre13) Création de fenêtres & d'Applets carre14) Les &laqo; Threads » multiples carre15) Informatique distribuée A) Passage et retour d'objets carreB) L'Interface Java Natif (JNI) carreC) Conseils pour une programation stylée en Java carreD) Resources
Texte original t Traducteur : Jérome Quelin
t
t
///
Ce chapitre contient 6 pages
1 2 3 4 5 6
\\\
t t t
t t t
t
t t t

Successful cloning

t

Pour un clonage réussi

t t t
Once you understand the details of implementing the clone( ) method, you’re able to create classes that can be easily duplicated to provide a local copy:
t Une fois les détails d'implémentation de clone() compris, il est facile de créer des classes facilement duplicables pour produire des copies locales :
t t t
//: appendixa:LocalCopy.java // Creating local copies with clone(). import java.util.*; class MyObject implements Cloneable { int i; MyObject(int ii) { i = ii; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { System.err.println("MyObject can't clone"); } return o; } public String toString() { return Integer.toString(i); } } public class LocalCopy { static MyObject g(MyObject v) { // Passing a reference, modifies outside object: v.i++; return v; } static MyObject f(MyObject v) { v = (MyObject)v.clone(); // Local copy v.i++; return v; } public static void main(String[] args) { MyObject a = new MyObject(11); MyObject b = g(a); // Testing reference equivalence, // not object equivalence: if(a == b) System.out.println("a == b"); else System.out.println("a != b"); System.out.println("a = " + a); System.out.println("b = " + b); MyObject c = new MyObject(47); MyObject d = f(c); if(c == d) System.out.println("c == d"); else System.out.println("c != d"); System.out.println("c = " + c); System.out.println("d = " + d); } } ///:~ t
//: appendixa:LocalCopy.java
// Créer des copies locales avec clone().
import java.util.*;

class MyObject implements Cloneable {
  int i;
  MyObject(int ii) { i = ii; }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      System.err.println("MyObject can't clone");
    }
    return o;
  }
  public String toString() {
    return Integer.toString(i);
  }
}

public class LocalCopy {
  static MyObject g(MyObject v) {
    // Passage par référence, modifie l'objet extérieur :
    v.i++;
    return v;
  }
  static MyObject f(MyObject v) {
    v = (MyObject)v.clone(); // Copie locale
    v.i++;
    return v;
  }
  public static void main(String[] args) {
    MyObject a = new MyObject(11);
    MyObject b = g(a);
    // On teste l'équivalence des références,
    // non pas l'équivalence des objets :
    if(a == b)
      System.out.println("a == b");
    else
      System.out.println("a != b");
    System.out.println("a = " + a);
    System.out.println("b = " + b);
    MyObject c = new MyObject(47);
    MyObject d = f(c);
    if(c == d)
      System.out.println("c == d");
    else
      System.out.println("c != d");
    System.out.println("c = " + c);
    System.out.println("d = " + d);
  }
} ///:~
t t t
First of all, clone( ) must be accessible so you must make it public. Second, for the initial part of your clone( ) operation you should call the base-class version of clone( ). The clone( ) that’s being called here is the one that’s predefined inside Object, and you can call it because it’s protected and thereby accessible in derived classes.
t Tout d'abord, clone() doit être accessible, il faut donc la rendre public. Ensuite, il faut que clone() commence par appeler la version de clone() de la classe de base. La méthode clone() appelée ici est celle prédéfinie dans Object, et on peut l'appeler car elle est protected et donc accessible depuis les classes dérivées.
t t t
Object.clone( ) figures out how big the object is, creates enough memory for a new one, and copies all the bits from the old to the new. This is called a bitwise copy, and is typically what you’d expect a clone( ) method to do. But before Object.clone( ) performs its operations, it first checks to see if a class is Cloneable—that is, whether it implements the Cloneable interface. If it doesn’t, Object.clone( ) throws a CloneNotSupportedException to indicate that you can’t clone it. Thus, you’ve got to surround your call to super.clone( ) with a try-catch block, to catch an exception that should never happen (because you’ve implemented the Cloneable interface).
t Object.clone() calcule la taille de l'objet, réserve assez de mémoire pour en créer un nouveau, et copie tous les bits de l'ancien dans le nouveau. On appelle cela une copie bit à bit, et c'est typiquement ce qu'on attend d'une méthode clone(). Mais avant que Object.clone() ne réalise ces opérations, elle vérifie d'abord que la classe est Cloneable - c'est à dire, si elle implémente l'interface Cloneable. Si ce n'est pas le cas, Object.clone() génère une exception CloneNotSupportedException pour indiquer qu'on ne peut la cloner. C'est pourquoi il faut entourer l'appel à super.clone() dans un bloc try-catch, pour intercepter une exception qui théoriquement ne devrait jamais arriver (parce qu'on a implémenté l'interface Cloneable).
t t t
In LocalCopy, the two methods g( ) and f( ) demonstrate the difference between the two approaches for argument passing. g( ) shows passing by reference in which it modifies the outside object and returns a reference to that outside object, while f( ) clones the argument, thereby decoupling it and leaving the original object alone. It can then proceed to do whatever it wants, and even to return a reference to this new object without any ill effects to the original. Notice the somewhat curious-looking statement:
t Dans LocalCopy, les deux méthodes g() et f() démontrent la différence entre les deux approches concernant le passage d'arguments. g() montre le passage par référence en modifiant l'objet extérieur et en retournant une référence à cet objet extérieur, tandis que f() clone l'argument, se détachant de lui et laissant l'objet original inchangé. Elle peut alors faire ce qu'elle veut, et même retourner une référence sur ce nouvel objet sans impacter aucunement l'original. À noter l'instruction quelque peu curieuse :
t t t
v = (MyObject)v.clone(); t
v = (MyObject)v.clone();
t t t
This is where the local copy is created. To prevent confusion by such a statement, remember that this rather strange coding idiom is perfectly feasible in Java because every object identifier is actually a reference. So the reference v is used to clone( ) a copy of what it refers to, and this returns a reference to the base type Object (because it’s defined that way in Object.clone( )) that must then be cast to the proper type.
t C'est ici que la copie locale est créée. Afin d'éviter la confusion induite par une telle instruction, il faut se rappeler que cet idiome plutôt étrange est tout à fait légal en Java parce que chaque identifiant d'objet est en fait une référence. La référence v est donc utilisée pour réaliser une copie de l'objet qu'il référence grâce à clone(), qui renvoie une référence au type de base Object (car c'est ainsi qu'est définie Object.clone()) qui doit ensuite être transtypée dans le bon type.
t t t
In main( ), the difference between the effects of the two different argument-passing approaches in the two different methods is tested. The output is:
t Dans main(), la différence entre les effets des deux approches de passage d'arguments est testée. La sortie est :
t t t
a == b a = 12 b = 12 c != d c = 47 d = 48 t
a == b
a = 12
b = 12
c != d
c = 47
d = 48
t t t
It’s important to notice that the equivalence tests in Java do not look inside the objects being compared to see if their values are the same. The == and != operators are simply comparing the references. If the addresses inside the references are the same, the references are pointing to the same object and are therefore “equal.” So what the operators are really testing is whether the references are aliased to the same object!
t Il est important de noter que les tests d'équivalence en Java ne regardent pas à l'intérieur des objets comparés pour voir si leurs valeurs sont les mêmes. Les opérateurs == et != comparent simplement les références. Si les adresses à l'intérieur des références sont les mêmes, les références pointent sur le même objet et sont donc « égales ». Les opérateurs testent donc si les références sont aliasées sur le même objet !
t t t

The effect of Object.clone( )

t

Le mécanisme de Object.clone( )

t t t
What actually happens when Object.clone( ) is called that makes it so essential to call super.clone( ) when you override clone( ) in your class? The clone( ) method in the root class is responsible for creating the correct amount of storage and making the bitwise copy of the bits from the original object into the new object’s storage. That is, it doesn’t just make storage and copy an Object—it actually figures out the size of the precise object that’s being copied and duplicates that. Since all this is happening from the code in the clone( ) method defined in the root class (that has no idea what’s being inherited from it), you can guess that the process involves RTTI to determine the actual object that’s being cloned. This way, the clone( ) method can create the proper amount of storage and do the correct bitcopy for that type.
t Que se passe-t-il réellement quand Object.clone() est appelé, qui rende si essentiel d'appeler super.clone() quand on redéfinit clone() dans une classe ? La méthode clone() dans la classe racine (ie, Object) est chargée de la réservation de la mémoire nécessaire au stockage et de la copie bit à bit de l'objet original dans le nouvel espace de stockage. C'est à dire, elle ne crée pas seulement l'emplacement et copie un Object - elle calcule précisément la taille de l'objet copié et le duplique. Puisque tout cela se passe dans le code de la méthode clone() définie dans la classe de base (qui n'a aucune idée de ce qui est dérivé à partir d'elle), vous pouvez deviner que le processus implique RTTI pour déterminer quel est réellement l'objet cloné. De cette façon, la méthode clone() peut réserver la bonne quantité de mémoire et réaliser une copie bit à bit correcte pour ce type.
t t t
Whatever you do, the first part of the cloning process should normally be a call to super.clone( ). This establishes the groundwork for the cloning operation by making an exact duplicate. At this point you can perform other operations necessary to complete the cloning.
t Quoi qu'on fasse, la première partie du processus de clonage devrait être un appel à super.clone(). Ceci pose les fondations de l'opération de clonage en créant une copie parfaite. On peut alors effectuer les autres opérations nécessaires pour terminer le clonage.
t t t
To know for sure what those other operations are, you need to understand exactly what Object.clone( ) buys you. In particular, does it automatically clone the destination of all the references? The following example tests this:
t Afin de savoir exactement quelles sont ces autres opérations, il faut savoir ce que Object.clone() nous fournit. En particulier, clone-t-il automatiquement la destination de toutes les références ? L'exemple suivant teste cela :
t t t
//: appendixa:Snake.java // Tests cloning to see if destination // of references are also cloned. public class Snake implements Cloneable { private Snake next; private char c; // Value of i == number of segments Snake(int i, char x) { c = x; if(--i > 0) next = new Snake(i, (char)(x + 1)); } void increment() { c++; if(next != null) next.increment(); } public String toString() { String s = ":" + c; if(next != null) s += next.toString(); return s; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { System.err.println("Snake can't clone"); } return o; } public static void main(String[] args) { Snake s = new Snake(5, 'a'); System.out.println("s = " + s); Snake s2 = (Snake)s.clone(); System.out.println("s2 = " + s2); s.increment(); System.out.println( "after s.increment, s2 = " + s2); } } ///:~ t
//: appendixa:Snake.java
// Teste le clonage pour voir si la destination
// des références sont aussi clonées.

public class Snake implements Cloneable {
  private Snake next;
  private char c;
  // Valeur de i == nombre de segments
  Snake(int i, char x) {
    c = x;
    if(--i > 0)
      next = new Snake(i, (char)(x + 1));
  }
  void increment() {
    c++;
    if(next != null)
      next.increment();
  }
  public String toString() {
    String s = ":" + c;
    if(next != null)
      s += next.toString();
    return s;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      System.err.println("Snake can't clone");
    }
    return o;
  }
  public static void main(String[] args) {
    Snake s = new Snake(5, 'a');
    System.out.println("s = " + s);
    Snake s2 = (Snake)s.clone();
    System.out.println("s2 = " + s2);
    s.increment();
    System.out.println(
      "after s.increment, s2 = " + s2);
  }
} ///:~
t t t
A Snake is made up of a bunch of segments, each of type Snake. Thus, it’s a singly linked list. The segments are created recursively, decrementing the first constructor argument for each segment until zero is reached. To give each segment a unique tag, the second argument, a char, is incremented for each recursive constructor call.
t Un Snake est composé d'un ensemble de segments, chacun de type Snake. C'est donc une liste chaînée simple. Les segments sont créés récursivement, en décrémentant le premier argument du constructeur pour chaque segment jusqu'à ce qu'on atteigne zéro. Afin de donner à chaque segment une étiquette unique, le deuxième argument, un char, est incrémenté pour chaque appel récursif au constructeur.
t t t
The increment( ) method recursively increments each tag so you can see the change, and the toString( ) recursively prints each tag. The output is:
t La méthode increment() incrémente récursivement chaque étiquette afin de pouvoir observer les modifications, et toString() affiche récursivement chaque étiquette. La sortie est la suivante :
t t t
s = :a:b:c:d:e s2 = :a:b:c:d:e after s.increment, s2 = :a:c:d:e:f t
s = :a:b:c:d:e
s2 = :a:b:c:d:e
after s.increment, s2 = :a:c:d:e:f
t t t
This means that only the first segment is duplicated by Object.clone( ), therefore it does a shallow copy. If you want the whole snake to be duplicated—a deep copy—you must perform the additional operations inside your overridden clone( ).
t Ceci veut dire que seul le premier segment est dupliqué par Object.clone(), qui ne réalise donc qu'une copie superficielle. Si on veut dupliquer tout le Snake - une copie profonde - il faut réaliser d'autres opérations dans la méthode clone() redéfinie.
t t t
You’ll typically call super.clone( ) in any class derived from a cloneable class to make sure that all of the base-class operations (including Object.clone( )) take place. This is followed by an explicit call to clone( ) for every reference in your object; otherwise those references will be aliased to those of the original object. It’s analogous to the way constructors are called—base-class constructor first, then the next-derived constructor, and so on to the most-derived constructor. The difference is that clone( ) is not a constructor, so there’s nothing to make it happen automatically. You must make sure to do it yourself.
t Typiquement il faudra donc faire un appel à super.clone() dans chaque classe dérivée d'une classe cloneable pour s'assurer que toutes les opérations de la classe de base (y compris Object.clone()) soient effectuées. Puis cela sera suivi par un appel explicite à clone() pour chaque référence contenue dans l'objet ; sinon ces références seront aliasées sur celles de l'objet original. Le mécanisme est le même que lorsque les constructeurs sont appelés - constructeur de la classe de base d'abord, puis constructeur de la classe dérivée suivante, et ainsi de suite jusqu'au constructeur de la classe dérivée la plus lointaine de la classe de base. La différence est que clone() n'est pas un constructeur, il n'y a donc rien qui permette d'automatiser le processus. Il faut s'assurer de le faire soi-même.
t t t

Cloning a composed object

t

Cloner un objet composé

t t t
There’s a problem you’ll encounter when trying to deep copy a composed object. You must assume that the clone( ) method in the member objects will in turn perform a deep copy on their references, and so on. This is quite a commitment. It effectively means that for a deep copy to work you must either control all of the code in all of the classes, or at least have enough knowledge about all of the classes involved in the deep copy to know that they are performing their own deep copy correctly.
t Il se pose un problème quand on essaye de faire une copie profonde d'un objet composé. Il faut faire l'hypothèse que la méthode clone() des objets membres va à son tour réaliser une copie profonde de leurs références, et ainsi de suite. Il s'agit d'un engagement. Cela veut dire que pour qu'une copie profonde fonctionne il faut soit contrôler tout le code dans toutes les classes, soit en savoir suffisamment sur les classes impliquées dans la copie profonde pour être sûr qu'elles réalisent leur propre copie profonde correctement.
t t t
This example shows what you must do to accomplish a deep copy when dealing with a composed object:
t Cet exemple montre ce qu'il faut accomplir pour réaliser une copie profonde d'un objet composé :
t t t
//: appendixa:DeepCopy.java // Cloning a composed object. class DepthReading implements Cloneable { private double depth; public DepthReading(double depth) { this.depth = depth; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(System.err); } return o; } } class TemperatureReading implements Cloneable { private long time; private double temperature; public TemperatureReading(double temperature) { time = System.currentTimeMillis(); this.temperature = temperature; } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(System.err); } return o; } } class OceanReading implements Cloneable { private DepthReading depth; private TemperatureReading temperature; public OceanReading(double tdata, double ddata){ temperature = new TemperatureReading(tdata); depth = new DepthReading(ddata); } public Object clone() { OceanReading o = null; try { o = (OceanReading)super.clone(); } catch(CloneNotSupportedException e) { e.printStackTrace(System.err); } // Must clone references: o.depth = (DepthReading)o.depth.clone(); o.temperature = (TemperatureReading)o.temperature.clone(); return o; // Upcasts back to Object } } public class DeepCopy { public static void main(String[] args) { OceanReading reading = new OceanReading(33.9, 100.5); // Now clone it: OceanReading r = (OceanReading)reading.clone(); } } ///:~ t
//: appendixa:DeepCopy.java
// Clonage d'un objet composé.

class DepthReading implements Cloneable {
  private double depth;
  public DepthReading(double depth) {
    this.depth = depth;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace(System.err);
    }
    return o;
  }
}

class TemperatureReading implements Cloneable {
  private long time;
  private double temperature;
  public TemperatureReading(double temperature) {
    time = System.currentTimeMillis();
    this.temperature = temperature;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace(System.err);
    }
    return o;
  }
}

class OceanReading implements Cloneable {
  private DepthReading depth;
  private TemperatureReading temperature;
  public OceanReading(double tdata, double ddata){
    temperature = new TemperatureReading(tdata);
    depth = new DepthReading(ddata);
  }
  public Object clone() {
    OceanReading o = null;
    try {
      o = (OceanReading)super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace(System.err);
    }
    // On doit cloner les références :
    o.depth = (DepthReading)o.depth.clone();
    o.temperature =
      (TemperatureReading)o.temperature.clone();
    return o; // Transtypage en Object
  }
}

public class DeepCopy {
  public static void main(String[] args) {
    OceanReading reading =
      new OceanReading(33.9, 100.5);
    // Maintenant on le clone :
    OceanReading r =
      (OceanReading)reading.clone();
  }
} ///:~
t t t
DepthReading and TemperatureReading are quite similar; they both contain only primitives. Therefore, the clone( ) method can be quite simple: it calls super.clone( ) and returns the result. Note that the clone( ) code for both classes is identical.
t DepthReading et TemperatureReading sont quasi identiques ; elles ne contiennent toutes les deux que des scalaires. La méthode clone() est donc relativement simple : elle appelle super.clone() et renvoie le résultat. Notez que le code de clone() des deux classes est identique.
t t t
OceanReading is composed of DepthReading and TemperatureReading objects and so, to produce a deep copy, its clone( ) must clone the references inside OceanReading. To accomplish this, the result of super.clone( ) must be cast to an OceanReading object (so you can access the depth and temperature references).
t OceanReading est composée d'objets DepthReading et TemperatureReading ; pour réaliser une copie profonde, sa méthode clone() doit donc cloner les références à l'intérieur de OceanReading. Pour réaliser ceci, le résultat de super.clone() doit être transtypé dans un objet OceanReading (afin de pouvoir accéder aux références depth et temperature).
t t t

A deep copy with ArrayList

t

Copie profonde d'une ArrayList

t t t
Let’s revisit the ArrayList example from earlier in this appendix. This time the Int2 class is cloneable, so the ArrayList can be deep copied:
t Reprenons l'exemple ArrayList exposé plus tôt dans cette annexe. Cette fois-ci la classe Int2 est cloneable, on peut donc réaliser une copie profonde de l'ArrayList :
t t t
//: appendixa:AddingClone.java // You must go through a few gyrations // to add cloning to your own class. import java.util.*; class Int2 implements Cloneable { private int i; public Int2(int ii) { i = ii; } public void increment() { i++; } public String toString() { return Integer.toString(i); } public Object clone() { Object o = null; try { o = super.clone(); } catch(CloneNotSupportedException e) { System.err.println("Int2 can't clone"); } return o; } } // Once it's cloneable, inheritance // doesn't remove cloneability: class Int3 extends Int2 { private int j; // Automatically duplicated public Int3(int i) { super(i); } } public class AddingClone { public static void main(String[] args) { Int2 x = new Int2(10); Int2 x2 = (Int2)x.clone(); x2.increment(); System.out.println( "x = " + x + ", x2 = " + x2); // Anything inherited is also cloneable: Int3 x3 = new Int3(7); x3 = (Int3)x3.clone(); ArrayList v = new ArrayList(); for(int i = 0; i < 10; i++ ) v.add(new Int2(i)); System.out.println("v: " + v); ArrayList v2 = (ArrayList)v.clone(); // Now clone each element: for(int i = 0; i < v.size(); i++) v2.set(i, ((Int2)v2.get(i)).clone()); // Increment all v2's elements: for(Iterator e = v2.iterator(); e.hasNext(); ) ((Int2)e.next()).increment(); // See if it changed v's elements: System.out.println("v: " + v); System.out.println("v2: " + v2); } } ///:~ t
//: appendixa:AddingClone.java
// Il faut apporter quelques modifications
// pour que vos classes soient cloneables.
import java.util.*;

class Int2 implements Cloneable {
  private int i;
  public Int2(int ii) { i = ii; }
  public void increment() { i++; }
  public String toString() {
    return Integer.toString(i);
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      System.err.println("Int2 can't clone");
    }
    return o;
  }
}

// Une fois qu'elle est cloneable, l'héritage
// ne supprime pas cette propriété :
class Int3 extends Int2 {
  private int j; // Automatiquement dupliqué
  public Int3(int i) { super(i); }
}

public class AddingClone {
  public static void main(String[] args) {
    Int2 x = new Int2(10);
    Int2 x2 = (Int2)x.clone();
    x2.increment();
    System.out.println(
      "x = " + x + ", x2 = " + x2);
    // Tout objet hérité est aussi cloneable :
    Int3 x3 = new Int3(7);
    x3 = (Int3)x3.clone();

    ArrayList v = new ArrayList();
    for(int i = 0; i < 10; i++ )
      v.add(new Int2(i));
    System.out.println("v: " + v);
    ArrayList v2 = (ArrayList)v.clone();
    // Maintenant on clone chaque élément :
    for(int i = 0; i < v.size(); i++)
      v2.set(i, ((Int2)v2.get(i)).clone());
    // Incrémente tous les éléments de v2 :
    for(Iterator e = v2.iterator();
        e.hasNext(); )
      ((Int2)e.next()).increment();
    // Vérifie si les éléments de v ont été modifiés :
    System.out.println("v: " + v);
    System.out.println("v2: " + v2);
  }
} ///:~
t t t
Int3 is inherited from Int2 and a new primitive member int j is added. You might think that you’d need to override clone( ) again to make sure j is copied, but that’s not the case. When Int2’s clone( ) is called as Int3’s clone( ), it calls Object.clone( ), which determines that it’s working with an Int3 and duplicates all the bits in the Int3. As long as you don’t add references that need to be cloned, the one call to Object.clone( ) performs all of the necessary duplication, regardless of how far down in the hierarchy clone( ) is defined.
t Int3 est dérivée de Int2 et un nouveau membre scalaire int j a été ajouté. On pourrait croire qu'il faut redéfinir clone() pour être sûr que j soit copié, mais ce n'est pas le cas. Lorsque la méthode clone() de Int2 est appelée à la place de la méthode clone() de Int3, elle appelle Object.clone(), qui détermine qu'elle travaille avec un Int3 et duplique tous les bits de Int3. Tant qu'on n'ajoute pas de références qui ont besoin d'être clonées, l'appel à Object.clone() réalise toutes les opérations nécessaires au clonage, sans se préoccuper de la profondeur hiérarchique où clone() a été définie.
t t t
You can see what’s necessary in order to do a deep copy of an ArrayList: after the ArrayList is cloned, you have to step through and clone each one of the objects pointed to by the ArrayList. You’d have to do something similar to this to do a deep copy of a HashMap.
t Pour réaliser une copie profonde d'une ArrayList, il faut donc la cloner, puis la parcourir et cloner chacun des objets pointés par l'ArrayList. Un mécanisme similaire serait nécessaire pour réaliser une copie profonde d'un HashMap.
t t t
The remainder of the example shows that the cloning did happen by showing that, once an object is cloned, you can change it and the original object is left untouched.
t Le reste de l'exemple prouve que le clonage s'est bien passé en montrant qu'une fois cloné, un objet peut être modifié sans que l'objet original n'en soit affecté.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel