Cloner un objet


Pattern Prototype

 

clonage par défaut

Source de Clone1.java
import java.util.*;
public class Clone1 {
  public static void main(String[] args)  {
    Vector vect = new Vector();
    Puce1 puce =  new Puce1("pupuce");
    vect.add(puce);
    Vector vectClone = (Vector) vect.clone();
    System.out.println("element 0 du vecteur clone : "
                      + vectClone.elementAt(0));
    puce.nom = new String("zezette");
    System.out.println("changement de string"
                      +"\nelement 0 du vecteur original : "
                      + vect.elementAt(0)
                      +"\nelement 0 du vecteur clone : "
                      + vectClone.elementAt(0));
  }
}
class Puce1 {
  String nom;
  public Puce1(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
}

EXECUTION
element 0 du vecteur clone : Puce1@108786b : pupuce
changement de string
element 0 du vecteur original : Puce1@108786b : zezette
element 0 du vecteur clone : Puce1@108786b : zezette

  

  

  • les lignes de la classe :
    • la méthode clone a produit une copie du vecteur, mais les objets éléments du vecteur sont les mêmes
  • La méthode clone()
    • produit une "copie" de l'objet
    • retourne un Object, donc nécessite un cast pour récupérer le bon type
    • est héritée de la classe Object, mais est protected
    • par contre, elle est publique donc redéfinie dans la classe Vector

Cloneable

Source de Clone3.java
import java.util.*;
public class Clone3 {
  public static void main(String[] args)  {
    Puce3 mapuce =  new Puce3("pupuce");
    System.out.println("puce : " + mapuce);
    mapuce.nom = new String("zezette");
    System.out.println("changement de nom de mapuce"
                      +"\nmapuce : " + mapuce);
    Puce3 puceClone = (Puce3) mapuce.clone();
    System.out.println("puce clone : " + puceClone);
    mapuce.nom = new String("fifine");
    System.out.println("changement de nom de mapuce"
                      +"\npuce clone : " + puceClone);
  }
}
class Puce3 implements Cloneable {
  String nom;
  public Puce3(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
  public Object clone() {
    try {
      return super.clone();
    }
    catch (CloneNotSupportedException e) {
      throw new InternalError(e.getMessage());
    }
  }
}
EXECUTION
puce : Puce3@1add2dd : pupuce
changement de nom de mapuce
mapuce : Puce3@1add2dd : zezette
puce clone : Puce3@8ed465 : zezette
changement de nom de mapuce
puce clone : Puce3@8ed465 : zezette
  • les lignes de la classe :
    • La classe Puce a désormais une méthode clone() correcte :
      • l'"adresse" de l'objet cloné est différente de celui d'origine (visible avec l'appel à toString() de Object)
    • en fait, après clonage, les attributs nom des 2 puces pointent sur le même objet String, mais c'est un objet "constant" (de contenu inchangeable)

 

clonage superficiel

Source de Clone2.java
import java.util.*;
public class Clone2 {
  public static void main(String[] args)  {
    Vector vect = new Vector();
    Puce2 puce =  new Puce2("pupuce");
    vect.add(puce);
    Vector vectClone = (Vector) vect.clone();
    System.out.println("element 0 du vecteur clone : "
                      + vectClone.elementAt(0));
    puce.nom = new String("zezette");
    System.out.println("changement de string"
                      +"\nelement 0 du vecteur original : "
                      + vect.elementAt(0)
                      +"\nelement 0 du vecteur clone : "
                      + vectClone.elementAt(0));
  }
}
class Puce2 implements Cloneable {
  String nom;
  public Puce2(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
  public Object clone() {
    try {
      return super.clone();
    }
    catch (CloneNotSupportedException e) {
      throw new InternalError(e.getMessage());
    }
  }
}
EXECUTION
element 0 du vecteur clone : Puce2@1add2dd : pupuce
changement de string
element 0 du vecteur original : Puce2@1add2dd : zezette
element 0 du vecteur clone : Puce2@1add2dd : zezette
  • les lignes de la classe :
    • la classe Puce2 est Cloneable
    • mais l'implémentation de clone() par Vector est visiblement une copie superficielle

Clonage profond

Source de Clone5.java
import java.util.*;
import java.io.*;
public class Clone5 {
  public static void main(String[] args)  {
    Vector vect = new Vector();
    Puce5 mapuce = new Puce5("pupuce");
    vect.add(mapuce);
    vect.add(new Puce5("zezette"));
    vect.add(mapuce);
    System.out.println("vector : ");
    for (int i=0 ; i < vect.size(); i++)
      System.out.println(" - " + vect.elementAt(i));
    try {
      Vector vectClone = (Vector) serialClone(vect);
      System.out.println("vector apres serialClone: ");
      for (int i=0 ; i < vectClone.size(); i++)
        System.out.println(" - " + vectClone.elementAt(i));
    }
    catch(Exception e) {
      System.out.println(e.getMessage());
    }
  }
  static Object serialClone(final Serializable objet)
         throws IOException, ClassNotFoundException
   {
     final PipedOutputStream pipeOut = new PipedOutputStream();
     PipedInputStream pipeIn = new PipedInputStream(pipeOut);
     Thread serialiseur = new Thread() 
       {
	 public void run() {
	   ObjectOutputStream out = null;
	   try {
	     out = new ObjectOutputStream(pipeOut);
	     out.writeObject(objet);
	   }
	   catch(IOException e) {}
	   finally {
	     try { 
               out.close(); 
             } 
             catch (Exception e) {}
           }
         }
       };
     serialiseur.start();  
     ObjectInputStream in = new ObjectInputStream(pipeIn);
     return in.readObject();
   }
}
class Puce5 implements Serializable {
  String nom;
  public Puce5(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
}
EXECUTION
vector :
 - Puce5@bd0108 : pupuce
 - Puce5@8ed465 : zezette
 - Puce5@bd0108 : pupuce
vector apres serialClone:
 - Puce5@e7b241 : pupuce
 - Puce5@167d940 : zezette
 - Puce5@e7b241 : pupuce

 

clonage et héritage

Source de Clone4.java
import java.util.*;
public class Clone4 {
  public static void main(String[] args)  {
    Puce4 mapuce =  new Puce4("pupuce");
    System.out.println("puce : " + mapuce);
    Object puceClone =  mapuce.clone();
    System.out.println("puce clone : getClass= " 
                      + puceClone.getClass());
    PuceSavante4 einstein =  new PuceSavante4("albert");
    System.out.println("puce savante : " + einstein);
    Object einsteinClone =  einstein.clone();
    System.out.println("puce  savante clone : getClass= " 
                      + einsteinClone.getClass());
    Poux4 monpoux =  new Poux4("pouh");
    System.out.println("poux : " + monpoux);
    Object pouxClone =  monpoux.clone();
    System.out.println("poux clone : getClass= " 
                      + pouxClone.getClass());
    PouxRepus4 poupou =  new PouxRepus4("poupou");
    System.out.println("poux repus : " + poupou);
    Object poupouClone =  poupou.clone();
    System.out.println("poux repus  clone : getClass= " 
                      + poupouClone.getClass());
  }
}
class Puce4 implements Cloneable {
  String nom;
  public Puce4(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
  public Object clone() {
    try {
      return super.clone();
    }
    catch (CloneNotSupportedException e) {
      throw new InternalError(e.getMessage());
    }
  }
}
class PuceSavante4  extends Puce4 {
  public PuceSavante4(String n) {
    super(n);
  }
  int compte() {
    return (int)(Math.random()*100);
  }
}
class Poux4 implements Cloneable {
  String nom;
  public Poux4(String n) {
    nom = n;
  }
  public String toString() {
    return super.toString() + " : " + nom;
  }
  public Object clone() {
    return new Poux4(new String(nom)); // MAUVAIS !
  }
}
class PouxRepus4  extends Poux4 {
  public PouxRepus4(String n) {
    super(n);
  }
  void rote(String rot) {
    System.out.println(rot);
  }
}
EXECUTION
puce : Puce4@1add2dd : pupuce
puce clone : getClass= class Puce4
puce savante : PuceSavante4@11a698a : albert
puce  savante clone : getClass= class PuceSavante4
poux : Poux4@7ced01 : pouh
poux clone : getClass= class Poux4
poux repus : PouxRepus4@765291 : poupou
poux repus  clone : getClass= class Poux4

 

exercice