Bonjour,
j'ai une classe représentant une Personne, les attributs sont:
nom, prénom et sexe.
Je dois surcharger la méthode clone() en faisant un deep copy..
Je ne vois vraiment pas comment écrire cette méthode.
Pouvez vous m'aider?
Merci ;)
Version imprimable
Bonjour,
j'ai une classe représentant une Personne, les attributs sont:
nom, prénom et sexe.
Je dois surcharger la méthode clone() en faisant un deep copy..
Je ne vois vraiment pas comment écrire cette méthode.
Pouvez vous m'aider?
Merci ;)
bonjour,
La réponse est la : clonage
Il te suffit simplement d'implémenter la méthode clone dans ta Classe Personnes :
Code:
1
2
3
4
5 @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return new Person(this.name, this.lastName, this.sexe); }
Salut,
Sauf que ceci est incorrect puisque tu ne respectes pas les règles du cloneage !
:arrow: Il ne faut pas utiliser un constructeur mais appeler la méthode clone() hérité de Object, en implémentant Cloneable.
Exemple "basique" :
:arrow: Il est inutile de dupliquer la valeur pour le "sexe", puisqu'il s'agit d'un type primitif et que le clone copiera alors sa valeur.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 class Person implements Cloneable { private String nom; private String prenom; private Date birthDay; private char sexe; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
Pour les références c'est un peu plus compliqué car c'est la copie de la référence qui est effectué. Donc les deux références pointent vers le même objet en mémoire et il faut donc protéger cela par une copie explicite... sauf pour les types immuables (comme String) où cela est inutile et même contre-productif !
Donc cela devrait plutôt ressembler à ceci :
Maintenant on peut encore améliorer cela de trois manière :Code:
1
2
3
4
5
6
7
8
9 @Override protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); // On duplique l'attribut birthDay, car il n'est pas immuable : cloned.birthDay = (Date) cloned.birthDay.clone(); return cloned; }
- En supprimant l'exception de la déclaration de méthode. En effet cette dernière ne remontera que dans le cas où l'on implémente plus Cloneable. Inutile de se trainer une tel exception. Il est préférable de la cacher :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 @Override public Object clone() { try { Person cloned = (Person) super.clone(); cloned.birthDay = (Date) cloned.birthDay.clone(); return cloned; } catch (CloneNotSupportedException e) { // On remonte l'exception englobé dans une RuntimeException, // afin d'être quand même averti d'un éventuel problème : throw new RuntimeException(e); } }
- Selon les besoins, en déclarant le classe public afin de faciliter son utilisation depuis l'extérieur (ce qui est autorisé par le langage).
- Enfin, depuis Java 5.0 il est possible de changer le type de retour, afin d'éviter un nouveau cast en sortie...
Ce qui donnerait au final :
a++Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 @Override public Person clone() { try { Person cloned = (Person) super.clone(); cloned.birthDay = (Date) cloned.birthDay.clone(); return cloned; } catch (CloneNotSupportedException e) { // On remonte l'exception englobé dans une RuntimeException, // afin d'être quand même averti d'un éventuel problème : throw new RuntimeException(e); } }
Merci pour votre aide, donc si ma classe contient des attributs qui sont uniquement des String, des int, des char et des double, je peux me contenter de:
?????????Code:
1
2
3
4
5 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
Autre question: en quoi cette méthode utilise le DEEP COPY?
Merci d'avance.
comme tu n'as que des types primitif, elle n'utilise pas le deep copy. Comme la javadoc le dit, l'implémentation dans Object utilise le "shallow copy". Pour chaque attribut mutable de ton objet, tu devra donc après faire, à la main, une nouvelle instance, comme adiguba te l'a montré avec un date.
Merci pour la réponse.
Mais si on me demande de faire une méthode clone() en utilisant une deep copy et que ma classe contient que des attributs de type double et string... Je fais quoi? :lol:
Bon je m'incruste :mrgreen: mais je comprends pas en quoi ce qu'il y a dessus est une bonne pratique ???Citation:
En supprimant l'exception de la déclaration de méthode. En effet cette dernière ne remontera que dans le cas où l'on implémente plus Cloneable. Inutile de se trainer une tel exception. Il est préférable de la cacher :
Code :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 @Override public Object clone() { try { Person cloned = (Person) super.clone(); cloned.birthDay = (Date) cloned.birthDay.clone(); return cloned; } catch (CloneNotSupportedException e) { // On remonte l'exception englobé dans une RuntimeException, // afin d'être quand même averti d'un éventuel problème : throw new RuntimeException(e); } }
CloneNotSupportedException peut être remonté dans le cas où l'objet n'implémente pas l'interface clonable mais aussi dans le cas où la méthode a été overridé et que l'objet ne devrait pas être cloné.
Dans le deuxième cas ne vaudrait il mieux pas laisser le throws CloneNotSupportedException ??
Merci de m'éclairer :calim2:
Il n'est pas très correct que le type courant soit cloneable mais qu'un type enfants ne le soit plus. Et si c'était le cas le type fils pourrait utiliser une RuntimeException...
L'idée est d'éviter de se trainer une exception inutile dans 99% des cas, et qui risque d'être ignorée, ce qui pourrait s'avérer bien pire.
a++
Rien de particulier, une deep copy dans ce cas là est exactement la même chose qu'un shallow copy. Le clone sera bien entièrement indépendant de son créateur. Pour faire simple, tes attributs n'ayant aucune "profondeur" je vois pas quelle profondeur tu voudrais cloner ;)
D'accord.
Si Personne ne contenait que des types primitifs et String, je pourrais me contenter de ceci:
Ou il vaut mieux faire ceci:Code:
1
2
3
4
5 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
??Code:
1
2
3
4
5
6
7 @Override protected Object clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); return cloned; }
Merci d'avance.
le type casting ne sert à rien.
Merci :ccool:
Dernière chose: est ce mieux de mettre la méthode en protégé:
Ou en public:Code:
1
2
3
4
5 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }
??Code:
1
2
3
4
5 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); }
tout dépend de qui a besoin de cloner ton objet. Mais a priori, en public ce serait quand meme le plus propre :)
D'accord 8-)
Deux toutes dernières choses:
- pourquoi mettre protected Object clone()...
et non protected Person clone()... ?
- ma classe Person doit obligatoirement impémenter cloneable()?
Merci
La covariance de type de retour d'une méthode est une fonctionnalité valable qu'à partir de java 5, Avant et par principe on ne peut redéfinir une méthode qui a la même signature où on change juste le type de retour:
càd avant java 1.5
Il est préférable d'utiliser cette fonctionnalité qui va t'éviter de faire des cast inutile..:mrgreen:Code:
1
2
3
4
5
6
7 class A{ public A method(); } class B extends A{ public B method(); } //Génère une erreur de compilation
Enfin OUI il faut implémenter Cloneable sinon on aura une CloneNotSupportedException quand tu va appeler Person.clone()
Oui, ta classe doit impérativement implémenter Cloneable. Sans quoi tu auras à coup sûr une CloneNotSupportedOperation.
La méthode clone() est protected dans Object afin d'avoir une implémentation par défaut invisible à l'extérieur. Tu peux la rendre accessible en la marquant public lorsque tu implémentes clone();
Je te conseille vraiment de prendre la méthode telle qu'Adiguba l'a écrite, bien que je remplacerais "throw new RuntimeException" par "throw new UnsupportedOperationException", mais bon, les goûts et les couleurs...
Moi je suis d'accord avec adiGuba pour l'exception RuntimeException qui va encapsuler l'exception non runtime juste pour éviter d'avoir des try catch inutiles en appelant clone() ;)
UnsupportedOperationException va induire l'utilisateur à l'erreur en croyant qu'on ne peut appeler clone() alors qui a eu peut être une erreur interne c'est tout!
Comme je le disais, les goûts et les couleurs... La réponse d'adiguba suffisait amplement, mais tu désires que j'argumente donc :)
Petit exercice de comparaison de String :
- CloneNotSupportedException
- UnsupportedOperationException
Indice, cela se trouve en gras :mrgreen:
Le choix qu'on a entre RuntimeException et UnsupportedOperationException est plus sémantique qu'autre chose : préfère-t-on lancer une IOException ou une Exception ? Je suis partisan de l'IOException, d'autres en ont rien à faire et lancent une Exception. C'est pareil ici, sauf qu'elle ne sera a priori jamais lancée.
À y réfléchir, ne serait-il pas plus correct de lancer une Error dans ce cas ?