IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

Surcharger une méthode clone()


Sujet :

avec Java

  1. #1
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut Surcharger une méthode clone()
    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

  2. #2
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Points : 2 061
    Points
    2 061
    Par défaut
    bonjour,
    La réponse est la : clonage
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre du Club
    Inscrit en
    Novembre 2007
    Messages
    45
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 45
    Points : 60
    Points
    60
    Par défaut
    Il te suffit simplement d'implémenter la méthode clone dans ta Classe Personnes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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);
    	}

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par marcel_kobain Voir le message
    Il te suffit simplement d'implémenter la méthode clone dans ta Classe Personnes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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);
    	}
    Sauf que ceci est incorrect puisque tu ne respectes pas les règles du cloneage !

    Il ne faut pas utiliser un constructeur mais appeler la méthode clone() hérité de Object, en implémentant Cloneable.

    Exemple "basique" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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();
    	}
     
    }
    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.
    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 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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;
    	}
    Maintenant on peut encore améliorer cela de trois manière :
    1. 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 : Sélectionner tout - Visualiser dans une fenêtre à part
      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);
      		}
      	}
    2. 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).
    3. 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 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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);
    		}
    	}
    a++

  5. #5
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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.

  6. #6
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    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.

  7. #7
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    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?

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    333
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 333
    Points : 295
    Points
    295
    Par défaut
    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 : Sélectionner tout - Visualiser dans une fenêtre à part
    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);
    		}
    	}
    Bon je m'incruste mais je comprends pas en quoi ce qu'il y a dessus est une bonne pratique ???

    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

  9. #9
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par LittleBean Voir le message
    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é.
    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++

  10. #10
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Citation Envoyé par alex2746 Voir le message
    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?
    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

  11. #11
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    D'accord.
    Si Personne ne contenait que des types primitifs et String, je pourrais me contenter de ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @Override
    protected Object clone() throws CloneNotSupportedException {
    	return super.clone();
    }
    Ou il vaut mieux faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @Override
    protected Object clone() throws CloneNotSupportedException {
    	Person cloned = (Person) super.clone();
     
    	return cloned;
    }
    ??

    Merci d'avance.

  12. #12
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    le type casting ne sert à rien.

  13. #13
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    Merci

    Dernière chose: est ce mieux de mettre la méthode en protégé:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @Override
    protected Object clone() throws CloneNotSupportedException {
    	return super.clone();
    }
    Ou en public:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    @Override
    public Object clone() throws CloneNotSupportedException {
    	return super.clone();
    }
    ??

  14. #14
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    tout dépend de qui a besoin de cloner ton objet. Mais a priori, en public ce serait quand meme le plus propre

  15. #15
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    187
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 187
    Points : 51
    Points
    51
    Par défaut
    D'accord

    Deux toutes dernières choses:

    - pourquoi mettre protected Object clone()...
    et non protected Person clone()... ?

    - ma classe Person doit obligatoirement impémenter cloneable()?

    Merci

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2008
    Messages : 338
    Points : 402
    Points
    402
    Par défaut
    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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    Il est préférable d'utiliser cette fonctionnalité qui va t'éviter de faire des cast inutile..
    Enfin OUI il faut implémenter Cloneable sinon on aura une CloneNotSupportedException quand tu va appeler Person.clone()

  17. #17
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    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...

  18. #18
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par dingoth Voir le message
    bien que je remplacerais "throw new RuntimeException" par "throw new UnsupportedOperationException", mais bon, les goûts et les couleurs...
    Ca c'est juste un détail puisque cette exception ne devrait jamais remonter !
    L'important étant de bien remonter une exception "au cas où", afin de détecter immédiatement une éventuelle erreur de développement...

    a++

  19. #19
    Membre averti
    Profil pro
    Inscrit en
    Mars 2008
    Messages
    338
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2008
    Messages : 338
    Points : 402
    Points
    402
    Par défaut
    Citation Envoyé par dingoth Voir le message
    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!

  20. #20
    Membre expérimenté
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Points : 1 419
    Points
    1 419
    Par défaut
    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

    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 ?

Discussions similaires

  1. Surcharger une méthode dans une dll.
    Par Slashyguigui dans le forum C#
    Réponses: 5
    Dernier message: 22/09/2011, 09h15
  2. [Doctrine] Surcharger une méthode gérée par __call()
    Par Chekov dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 12/09/2009, 23h12
  3. Surcharger une méthode
    Par daddycorp dans le forum Langage
    Réponses: 6
    Dernier message: 16/12/2008, 10h55
  4. "Dé-surcharger" une méthode native javascript
    Par Takezo1584 dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 26/08/2007, 12h37
  5. [Custom Tags] Problème avec une surcharge de méthode
    Par Strab dans le forum Taglibs
    Réponses: 19
    Dernier message: 26/08/2005, 16h34

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo