Bonjour,
j'aimerai savoir comment faire pour cloner une classe mais en dupliquant également la valeur des attributs, ce que ne fait pas la méthode "clone()".
Merci
Version imprimable
Bonjour,
j'aimerai savoir comment faire pour cloner une classe mais en dupliquant également la valeur des attributs, ce que ne fait pas la méthode "clone()".
Merci
On "clone" des objets et non des classes...
Tu dois pour cela redéfinir la méthode clone pour qu'elle fasse ce que tu veux.
Code:
1
2
3
4
5
6
7 public MonObjet clone(MonObjet B){ MonObjet A=new MonObjet(); A.setAttribut1(B.getAttribut1); //le reste du traitement return A; }
Citation:
Envoyé par afrikha
FAUX !
Dans ton exemple, l'attribut B n'est pas dupliqué. L'attribut A et l'attribut B référencent la même valeur.
Moi je voudrais cloner les attributs également
Ce que tu peut faire, c'est prendre chaque attribut de la classe à cloner et les cloner et ensuite mettre le clone de ces attributs dans le clone de la classe.
Oui en gros je voulais savoir si il existait une méthode proche de la méthode clone() mais qui faisiat un clone total, c'est à dire qui duplique l'objet, ses attributs et la valeur des attributs.
Si cela n'existe pas, j'opterai alors pour une autre facon de faire, en l'occurence redéfinir la méthode clone et cloner mes attributs un par un.:?
Ah la la, je suis mal réveillé moi, mais bon ce n'est pas une raison :oops:
Je ne vois pas d'autres solutions à part celle proposé par wichtounet.
Le problème c'est que mon objet comporte des attributs de types différents : String ,int et des types Objet.Citation:
Envoyé par wichtounet
Or , la classe String par exemple, n'implémente pas l'interface Cloneable, ce qui signifie que pour cloner une valeur de type String, je suis obligé de faire dériver la classe String en une classe String1 qui va implémenter la classe Cloneable et tous mes attributs de type String devront être de type String1 : extrémement lourd...
Question stupide : Pourquoi ne pas appeler le constructeur dans la méthode clone ?
Je ne vois pas du tout l'intérêt, explique toi. (je rappele que je suis capable de cloner un objet mais pas la valeur de ses attributs)
C'était effectivement une question stupide, tu es quand même obligé de cloner tes attributs un à un.
Je regrette de ne pas pouvoir t'aider d'avantage :(
Salut,
Et surtout impossible : on ne peut pas étendre la classe String...Citation:
Envoyé par danyboy85
A la rigueur tu pourrais surement passer par la Reflection pour "cloner" tous les attributs qui implémente Cloneable (et encore il me semble que ce n'est pas une condition suffisante pour que ce soit possible).
Mais bien sûr cela ne marchera pas avec les objets non-cloneable...
Question : Pourquoi as-tu besoin de cloner tous les attributs de l'objet ???
a++
Bon les pros du java je vous est posé une colle on dirait;) pourtant je crois avoir trouvé la solution : l'introspection.
En effet la classe Fields implément l'interface Cloneable :
Edit : bien joué AdiGuba tu avais trouvé avant moiCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 public Object clone() throws CloneNotSupportedException { MonObjet objectCopie = (MonObjet)super.clone(); //dupliquer le contenu des attributs Field[] attributsClone = (Field[])this.getClass().getDeclaredFields().clone(); Field[] attributsObjectCopie = objectCopie.getClass().getDeclaredFields(); for (int i=0; i<attributsClone.length; i++) { attributsObjectCopie[i] = attributsClone[i]; } return objectCopie; }
Pour ce qui est de String, je pense pas que c'est un gros problème...Citation:
Envoyé par danyboy85
Du fait de son immuabilité, tu t'en fous un peu de prendre la même référence et en plus, c'est pas très dur d'en faire un clone.
Sauf que ton code est faux :mouarf:Citation:
Envoyé par danyboy85
Donc tu n'a pas cloner les attributs...
- La classe Field n'est pas Cloneable, et de toute manière elle représente une vue sur un attribut mais en aucun cas sa valeur.
- Tu ne clone pas des Fields mais un tableau de Field. Or lorsqu'on clone un tableau on ne clone que le conteneur et non pas le contenu (les objets des deux tableaux sont identiques).
Il faudrait que tu parcours le tableau de Field et que tu appelles la méthode get() pour récupérer la valeur de chaque attribut.
Ensuite si ce dernier est Cloneable, il faut essayer d'appeller la méthode clone() via reflection (puisqu'elle est déclaré protected par défaut tu ne pourra pas l'appeller directement).
Enfin si le cloneage à réussi il te faudra modifier la valeur de l'attribut avec la méthode set()...
Tout cela en gérant un grand nombre d'exception...
a++
En effet... tu as entièrement raison.
Bon si quelqu'un a une méthode plus simple je suis preneur.
Car j'ai besoin de 2 objets distincts, qui n'ont aucune référence commune.Citation:
Envoyé par adiGuba
En fait je crée un sorte d'éditeur HTML et lorsque l'utilisateur copie un bouton par exemple, le bouton copié doit avoir les mêmes propriétés que le bouton d'origine mais la modification d'une propiété de l'un ne doit en aucun cas modifier la valeur de la propriété de l'autre.
Hello,
Deux problèmes se posent à mon avis:
- est ce que en passant par l'introspection et sachant que tu vas récupérer un Object, est ce que le Object.clone() va te donner la méthode clone() de Oject ou de ta sous-classe (là je pense que la seconde proposition est vraie).
- et si jamais ton attribut est un autre objet avec des autres attributs, que vas-tu-faire ?
Donc pour avoir deux objects distincts c'est pas évident. Le deep clone c'est pas facile :mouarf:
A+
C'est quoi l'immuabilité ?Citation:
Envoyé par wichtounet
Ah bon et pourquoi ?Citation:
Envoyé par wichtounet
Et comment ?Citation:
Envoyé par wichtounet
Salut,
Pour les types primitifs, aucun souci de clonage.
Pour ce qui est des objets, pourquoi ne pas utiliser les constructeurs par copie ? Si ce sont des bons constructeurs, ils ne copient pas la référence mais bien l'objet en lui même. Exemple de la classe String :
Exactement ce que tu veux. Apres si ce sont tes propres objets, bah développes des constructeurs par copie qui invoquent en cascade des constructeurs par copie, etc etc :)Citation:
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string.
Je ferais ça moi ;)
Bon courage
Fred
edit : immuabilité veut dire que tu ne peux changer l'objet. Si tu fais par exemple :
c'est équivalent à :Code:
1
2 String s="coucou"; s=s+" c'est moi";
Code:
1
2 String s="coucou"; s=new String("coucou c'est moi");
- Oui c'est pas bête et ca POURRAIT résoudre mon problème cette idée de constructeur mais dans le cadre de mon appli c'est impossible à gérer (objets héritées, Factory...). En gros je ne connais pas toujours le type de l'objet que je dois clonerCitation:
Envoyé par mavina
- J'ai trouvé une autre méthode : la sérialisation. Bon je vais me faire lyncher par certains mais en tout cas ca fonctionne :
Code:
1
2
3
4
5
6
7
8
9
10
11 public Object copi() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); Object deepCopy = ois.readObject(); return deepCopy; }
Pour ton code sur la sérialisation, il manque des bloc try/finally afin de fermer correctement les flux.
Jette un coup d'oeil sur le tutoriel : java.io
http://java.sun.com/j2se/1.3/docs/ap...t.html#clone()
Citation:
Copying an object will typically entail creating a new instance of its class, but it also may require copying of internal data structures as well. No constructors are called.
- http://jakarta.apache.org/commons/la....Serializable)
Citation:
SerializationUtils
public static Object clone(Serializable object)
Deep clone an Object using serialization.
This is many times slower than writing clone methods by hand on all objects in your object graph. However, for complex object graphs, or for those that don't support deep cloning this can be a simple alternative implementation. Of course all the objects must be Serializable.
Parameters:
object - the Serializable object to clone
Returns:
the cloned object
Throws:
SerializationException - (runtime) if the serialization fails
- http://jakarta.apache.org/commons/lang/api-release/org/apache/commons/lang/ArrayUtils.html#clone(java.lang.Object[])
- http://java.sun.com/developer/Books/...a/Chapter3.pdf
;)
OK merciCitation:
Envoyé par afrikha
Je n'ai jamais parlé d'appeler la methode clone() ;)Citation:
Envoyé par g_rare
Il peut tres bien faire
Tout simplement ;)Citation:
MonObjet copie=new MonObjet(objetACopier);
Enfin, dans son cas c'est pas possible :aie:
Fred
(j'ai un peu tardé à poster)
Je suppose que tu dois venir de C++ où la copie d'objet est obligatoire dans ces cas là...
L'immuabilité est un des principales notions de Java (a mon sens en tout cas), et viens justement proposer une solution à ce style de problème.Citation:
Envoyé par danyboy85
Une classe immuable est une classe qui ne peut pas être modifié un fois qu'elle sont créée. On est obligé de créer une nouvelle instance...
C'est le cas d'un certain nombre de classe "conteneur", comme String, toutes les classes wrappers (Integer, Float, Double, Character...), Color, BigDecimal...
Les classes immuables se distinguent par un certain nombre de point :
La classe doit être final afin qu'on ne puissent pas en hérité (et potentiellement cassé l'immuabilité).
Tous les attributs devrait être déclaré final (afin d'être sûr qu'il ne soient pas modifié après l'initialisation) et private (afin qu'il ne soient pas modifié par une autre classe).
Aucune de ses méthodes ne modifient ses attributs (ou en tout cas ses attributs "utiles"). Donc pas de méthode set***()...
Si un attribut n'est pas lui-même immuable, on doit s'assurer de la recopie de sa valeur (avec clone() ou en créant un nouvel objet) et ne pas fournir la référence vers cet objet.
Si une classe est immuable, on peut alors l'utiliser simplement, sans aucune recopie ou cloneage, tout en étant sûr que sa valeur ne sera pas modifié à cause d'une référence qui traine... (c'est pour cela que String n'est pas cloneable)
Le petit bout de code suivant te montre bien cela, en comparant l'objet immuable Long et l'objet java.util.Date qui ne l'est pas :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public final class Main { private final Long longValue; private final Date dateValue; public Main(Long l, Date d) { this.longValue = l; this.dateValue = d; } @Override public String toString() { return longValue + " " + dateValue.getTime(); } public static void main(String[] args) { long value = 0; Long longValue = new Long(value); Date dateValue = new Date(value); // On crée un objet avec les valeurs 0 0 Main obj = new Main(longValue, dateValue); // On affiche l'objet System.out.println( obj ); // 0 0 // On modifie la valeur de l'objet 'longValue' // On est obligé d'en crée un nouveau : longValue = new Long( 15 ); // On affiche l'objet (rien n'a changé) : System.out.println( obj ); // 0 0 // On modifie la valeur de l'objet 'dateValue' // On n'est pas obligé d'en créer un nouveau // puisque la classe n'est pas immuable : dateValue.setTime( 15 ); // On affiche l'objet (qui a été modifié) : System.out.println( obj ); // 0 15 } }
Pour éviter ce type de problème, il aurait fallut créer une nouvel objet Date dans le constructeur :
Code:
1
2
3
4 public Main(Long l, Date d) { this.longValue = l; this.dateValue = new Date(d.getTime()); }
Le gros avantage de cette méthode par rapport à la recopie d'objet modifiable, c'est que tu ne crées une nouvelle instance que lorsque tu en as réellement besoin, et que tu évites un grand nombre de copie inutile...
Pour en revenir à ton problème : quel sont les types des objets que tu devras gérer ?
a++
PS : Juste une remarque :
En fait c'est équivalent à ceci :Citation:
Envoyé par mavina
Mais le résultat est le même : on a bien une nouvelle instance de String...Code:
1
2 String s="coucou"; s = new StringBuffer(s).append(" c'est moi").toString();
La classe String est un faux problème concernant le clonage. Etant une classe immuable, ton clone peut posséder la meme reference mais dans le cas d'un deepClone(). Puisque personne ne peut modifier sa valeur.Citation:
Envoyé par danyboy85
Si tout tes fields sont serializable, comme proposé quelques messages plus haut (zut je suis grillé :P ) tu peut alors utiliser une serialization/deserialization.
L'avantage avec ce mécanisme c'est qu'il respecte le graphe de reference.
C'est a dire que si ta classe A reference dans 2x champs le meme objet X
alors le clone aura une copie de X mais ces deux champs auront eux aussi la meme instance X.
A noté qu'un clone par serialization est trés couteux.