next up previous contents index
Next: Tableaux d'objets Up: Objets Previous: Chaînes de caractères

   
Clonage d'objets

   

Rappelons que l'affectation d'un objet à une variable écrit dans cette variable une référence à l'objet, mais ne crée pas un nouvel objet. Si l'on veut dupliquer un objet, on peut recourir à la méthode clone(), définie dans la classe Object. Celle-ci commence par tester si la classe de l'objet implémente l'interface Cloneable (voir § 3.1) ; si c'est le cas, elle effectue une copie superficielle de l'objet, et sinon, elle déclenche l'exception CloneNotSupportedException. Le transtypage est nécessaire, car clone() retourne un Object, pas un A :

  A a1 = new A();
  A a2 = (A)a1.clone();

Tous les types de tableaux sont des sous-types d'Object (ainsi que des interfaces Cloneable et java.io.Serializable). Ainsi, un tableau quelconque peut être affecté à une variable de type Object. Les types de tableaux héritent de toutes les méthodes publiques de la classe Object, à l'exception de la méthode clone(), qui est redéfinie (donc utilisable), et qui réalise une copie d'un tableau :

   int[] a = {1, 2, 3, 4};
   int[] b = (int[]) a.clone();

Cette méthode est utile quand les objets d'une structure de données sont exactement représentés par l'ensemble des valeurs de leurs champs : ceci est le cas si tous les champs sont d'un type primitif (par exemple, la classe des nombres complexes, qui a deux champs de type double), ou pour un tableau d'éléments de type primitif. Dans d'autres cas, par exemple pour des arbres binaires, la copie d'une structure ArbreBinaire n'entraine pas une copie de l'arbre complet, mais seulement de la racine :

    ArbreBinaire a = 
      new ACons(0, 
                new ACons(1, AVide.val(), AVide.val()),
                new ACons(2, AVide.val(), AVide.val()));
    ArbreBinaire a1 = a;
    ArbreBinaire a2 = (ArbreBinaire)a.clone();

où le type ArbreBinaire est une classe abstraite, dont les deux classes dérivées AVide et ACons représentent respectivement l'arbre vide et les arbres non vides.


 \begin{figurette}% latex2html id marker 2460
\begin{center}
\leavevmode
\fbox{...
...caption{Co-référencement par copie superficielle.}
\end{center} \end{figurette}

Alors que a1 et a désignent le même objet, la définition de a2 crée un nouvel objet, mais les objets au deuxième niveau de l'arbre sont identiques : il y a partage d'objets par co-référencement (figure 1.16). Une modification d'un n\oeud de a2 revient donc à une modification de a et de a1, ce qui n'est pas toujours souhaité.

  Il faut donc redéfinir la méthode clone() pour la classe Arbre afin qu'elle parcoure l'arbre et effectue des copies de tous les objets, et pas seulement de celui qui figure à sa racine (figure 1.16). Un parcours en profondeur donne la fonction suivante :

abstract class ArbreBinaire {
  // ...
  public abstract Object clone();
}

final class AVide extends ArbreBinaire {
  // ...
  public Object clone() {
    return this;
  }
}

class ACons extends ArbreBinaire {
  // ...
  public Object clone() {
    ArbreBinaire a = null, b = null;
    if (gauche != null) a = (ArbreBinaire)gauche.clone();
    if (droite != null) b = (ArbreBinaire)droite.clone(); 
    return new ACons(étiquette, a, b);
  }
}

En général, on souhaite que pour un objet x, la valeur de x == x.clone() soit false. Le cas de la classe AVide est une exception, puisqu'elle est définie afin de n'admettre qu'une seule instance, l'arbre vide : un clone de l'arbre vide sera donc identique à l'arbre vide.


 \begin{figurette}% latex2html id marker 2468
\begin{center}
\leavevmode
\fbox{...
...g/cell_clone.eps}
} \caption{Clonage d'un arbre.}
\end{center} \end{figurette}


next up previous contents index
Next: Tableaux d'objets Up: Objets Previous: Chaînes de caractères
R. Lalement
2000-10-23