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

Langage Java Discussion :

Interfaces et méthodes "Object"


Sujet :

Langage Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut Interfaces et méthodes "Object"
    Bonjour,

    Dans une Interface, je souhaite obliger l'implémentation de certaines méthodes, par exemple "toString()" :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public interface MonInterface{
      public String toString();
    }
    Seulement, les classes implémentants cette interface n'ont du coup pas besoin de déclarer la méthode, puisque présente dans Object. Alors que ça marche si j'utilise des classes abstraites :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public abstract class MaClasse{
      abstract public String toString();
    }
    En cherchant un peu, j'ai vu que beaucoup déclaraient toString dans les interfaces, pour obliger sa déclaration, et ainsi éviter de récupérer l'adresse de l'objet.

    Y a-t-il un moyen de forcer ses déclarations, ou c'est juste pour indiquer dans l'interface qu'il est souhaitable de redéclarer "toString()" (mais du coup, sans réel contrôle) ?

  2. #2
    Membre éprouvé Avatar de titourock
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2008
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2008
    Messages : 156
    Par défaut
    Bonjour,

    Tu dis "ça marche" pour les classes abstraites mais lorsqu'une classe B dérive d'une classe abstraite A, rien n'oblige B à définir toutes les méthodes de A (mais du coup B sera alors abstraite).
    Et lorsque tu implémentes une interface, il n'est pas "souhaitable" mais obligatoire d'implémenter ses méthodes.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Oui je parlais d'une méthode abstraite dans une classe abstraite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    abstract public classe MaClasse{
      abstract public String toString();
    }
    Dans ce cas, une classe héritière de "MaClasse" doit (si elle n'est pas abstraite) redéfinir cette méthode toString(). Hors ce n'est pas le cas avec une interface (donc non obligatoire).

    Donc, je réitère ma question

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    En cherchant un peu, j'ai vu que beaucoup déclaraient toString dans les interfaces, pour obliger sa déclaration, et ainsi éviter de récupérer l'adresse de l'objet.
    Y a-t-il un moyen de forcer ses déclarations, ou c'est juste pour indiquer dans l'interface qu'il est souhaitable de redéclarer "toString()" (mais du coup, sans réel contrôle) ?
    Si la méthode existe déjà dans une classe parente (comme dans l'exemple de toString(), déjà existante dans Object...) je ne pense pas que tu puisses forcer l'utilisateur de ton interface à la redéfinir.
    Mais de toutes façons, même si tu réussis à obliger l'utilisateur à réécrire dans son code une méthode, tu n'as aucun "réel contrôle" sur la redéfinition qu'il en fera ! Il peut très bien écrire par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public String toString() {
    		return getClass().getName() + '@' + Integer.toHexString(hashCode());
    	}
    ... ce qui correspond à la méthode toString() définit par défaut dans Object

    Si tu indiques dans ton interface qu'il serait préférable de redéfinir une méthode, ça me semble suffisant. L'utilisateur de l'interface peut de toutes manières mettre ce qu'il veut dans ses fonctions du moment qu'elles renvoient le bon type... y compris redéfinir exactement la même fonction que celle que tu voudrais qu'il surcharge... donc s'il veut faire n'importe quoi c'est son problème, et tu ne peux pas l'en empêcher.

    Petite question : pourquoi voudrais-tu obliger les classes-filles à redéfinir certaines méthodes ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    En fait, dans certaines classes utilisées pour la base de données, le développeur avait précisé dans l'interface "l'obligation" de surcharger toString() pour renvoyer l'identifiant d'une données.
    Certaines classes correspondent à une table, ces classes dépendent d'une classe abstraite où toString() est déclarée en abstract.
    Mais d'autres classes (des clés par exemple) implémente seulement une interface. Et je viens de remarquer dans l'une de ces classes que la méthode toString() manquait.

    Il y a bien d'autres cas où je le précise dans les interfaces (actions spécifiques, listeners, ...). C'est vrai que d'habitude, je change le nom de la méthode dans l'interface, pour que les classes mères utilisent quelque chose du genre (exemple un peu crade, mais c'est pour donner une idée hein) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    // actions communes
    public final void traiterAction(){
      // Traitement des actions communes (créer, enregistrer, ...)
      blabla
      // Appel de l'interface
      ((Interface)this).traiterActionSpécifique();
    }

  6. #6
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    En fait, dans certaines classes utilisées pour la base de données, le développeur avait précisé dans l'interface "l'obligation" de surcharger toString() pour renvoyer l'identifiant d'une données.
    Donc en fait tu veux obliger les classes filles à redéfinir une méthode parce que cette méthode doit renvoyer une valeur bien précise ?
    Le problème c'est que, comme je l'ai dit plus haut, même en redéfinissant la méthode on peut toujours mettre n'importe quoi dedans... Donc obliger l'utilisateur à redéfinir la méthode permettrait d'éviter un oubli mais ne garantirait pas la cohérence des traitements.
    La seule façon d'être sûr de la valeur renvoyée par la méthode serait de l'implémenter toi-même (=> classe (abstraite ou non) et non plus interface). Ce qui n'est pas toujours possible si ton interface se veut très générique... ou si elle doit rester une interface.
    Ce que tu peux faire c'est bien commenter ton interface - afin d'expliquer les conditions d'implémentation indispensables à un bon traitement - et de ton côté, dans ton code qui utilise des classes implémentant l'interface, bien gérer les erreurs qui pourraient provenir d'une mauvaise définition de la méthode. Mais obliger les classes utilisant l'interface à renvoyer un résultat cohérent avec ce que tu comptes en faire, ça n'est de toute façon pas possible.

  7. #7
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Oui c'est sur, mais c'est le cas pour toutes les méthodes de n'importe quelle classe ^^`:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public class JeFaisCeQueJeVeux {
        public boolean equals(Object obj) {
    	throw new NullPointerException("Et pan, je veux pas surcharger equals !");
        }
    }
    Donc après, que l'utilisateur définisse mal la méthode que je veux dans mon interface, c'est son problème
    Mais par contre, à cause de ça, il peut l'oublier puisque (en tout cas pour eclipse), la méthode n'est pas créée automatiquement.
    C'est juste par question de "simplicité", rappeler aux développeur de "penser à implémenter cette méthode" car elle me facilite la vie

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 764
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    Oui c'est sur, mais c'est le cas pour toutes les méthodes de n'importe quelle classe ^^ Donc après, que l'utilisateur définisse mal la méthode que je veux dans mon interface, c'est son problème
    Mais par contre il peut l'oublier
    C'est exactement ce que j'ai dit


    Si c'est juste pour éviter l'oubli... non, une interface ne peut pas obliger une classe à redéfinir explicitement une méthode.
    Une interface c'est un contrat qui dit "cette classe possédera telle et telle méthode, avec telle signature". Si ta classe possède bien la méthode, que ça soit par héritage ou non, le contrat est respecté.
    Si l'utilisateur oublie de lire la doc' et d'implémenter des méthodes cohérentes, c'est son problème

    Bon, après, c'est sûr qu'utiliser une méthode comme toString() pour des traitements spéciaux, c'est franchement pas terrible comme idée Il vaut mieux, comme tu en as parlé plus haut, utiliser un autre nom, qui en plus décrirait de façon explicite le but de la méthode (pour récupérer un identifiant, getId() c'est quand même vachement plus parlant que toString()).
    Dans l'idéal, il faudrait ajouter un getId (ou autre nom) dans l'interface, et remplacer tous les appels à toString par un getId... mais je suppose que si tu te poses ces questions c'est que tu n'as pas l'envie ou pas les moyens de refaire toute la bibliothèque .

  9. #9
    Membre Expert Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    Avril 2002
    Messages
    4 690
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : Avril 2002
    Messages : 4 690
    Par défaut
    Bon, après, c'est sûr qu'utiliser une méthode comme toString() pour des traitements spéciaux, c'est franchement pas terrible comme idée Il vaut mieux, comme tu en as parlé plus haut, utiliser un autre nom, qui en plus décrirait de façon explicite le but de la méthode (pour récupérer un identifiant, getId() c'est quand même vachement plus parlant que toString()).
    Ca ne me parait pas si bête que ça.
    C'est bien ce que fait l'API java à plusieurs endroits, par exemple pour les renderers par défaut des composants MVC de swings.

    Le truc moche mais que tu pourrais faire pour éviter la mauvaise utilisation ça serait de faire une vérification au runtime du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (objet.toString().equals(object.getClass().getName()+"@"+Integer.toHexString(object.getHashCode()))){
        throw new InvalidObjectException("object must overide equals() method behavoir");
    }

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Merci pour les réponses ! Ce qui est quand même embêtant, c'est qu'Eclipse, lors de la création d'une classe implémentant ce type d'interface, ne crée pas les méthodes déjà déclarées dans des classes parentes.

    P.S : A noter que je viens aussi de trouver le cas dans l'interface Comparator, avec la méthode equals(Object o).

  11. #11
    Membre éprouvé
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    Merci pour les réponses ! Ce qui est quand même embêtant, c'est qu'Eclipse, lors de la création d'une classe implémentant ce type d'interface, ne crée pas les méthodes déjà déclarées dans des classes parentes.

    P.S : A noter que je viens aussi de trouver le cas dans l'interface Comparator, avec la méthode equals(Object o).
    Meuh si, il le fait, du moins pour les interfaces.

    Il suffit de cocher la case 'Inherited Abstract Method' dans l'asssistant de création de classe et Eclipse te crée le stub des méthodes à implémenter.

  12. #12
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    C'était coché, il a bien mis la première (compare()), mais pas equals()

    Remarque : Peut être la version d'Eclipse (3.1), ou un autre paramètre de mon environnement.
    Remarque2 : Il ne propose pas non plus la méthode par le menu "Override/Implements method"

  13. #13
    Membre éprouvé
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    C'était coché, il a bien mis la première (compare()), mais pas equals()
    Oui c'est pourquoi j'ai dit :

    Citation Envoyé par Deadpool Voir le message
    Meuh si, il le fait, du moins pour les interfaces.
    Il suffit de cocher la case 'Inherited Abstract Method' dans l'asssistant de création de classe et Eclipse te crée le stub des méthodes à implémenter.
    En fait, ça marche pour toutes les méthodes abstraites héritées que ce soit d'une classe abstraite ou d'une interface.

    Citation Envoyé par JohnNC Voir le message
    Remarque2 : Il ne propose pas non plus la méthode par le menu "Override/Implements method"
    La méthode equals? C'est pas normal, elle devrait être dans la liste, c'est une méthode de la classe Object, implicitement héritée par toutes les classes

  14. #14
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Citation Envoyé par Deadpool Voir le message
    En fait, ça marche pour toutes les méthodes abstraites héritées que ce soit d'une classe abstraite ou d'une interface.
    D'une classe abstraite oui, d'une interface non (puisqu'il ne me met pas la méthode equals()).

    Citation Envoyé par Deadpool Voir le message
    La méthode equals? C'est pas normal, elle devrait être dans la liste, c'est une méthode de la classe Object, implicitement héritée par toutes les classes
    En fait, il me la propose de par la classe Object, mais pas de par l'interface.

    -> En fait, cette méthode ne serait pas dans l'interface, ça ne changerait rien pour Eclipse. En tout cas pour l'environnement que j'ai.

  15. #15
    Membre éprouvé
    Avatar de Deadpool
    Homme Profil pro
    Inscrit en
    Novembre 2005
    Messages
    1 312
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2005
    Messages : 1 312
    Par défaut
    Citation Envoyé par JohnNC Voir le message
    D'une classe abstraite oui, d'une interface non (puisqu'il ne me met pas la méthode equals()).
    La méthode equals n'est pas définie dans une interface mais dans la classe object. De plus elle n'est pas abstraite.

    C'est pour cela qu'elle n'est pas reportée.

  16. #16
    Membre confirmé
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    268
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 268
    Par défaut
    Citation Envoyé par Deadpool Voir le message
    La méthode equals n'est pas définie dans une interface mais dans la classe object. De plus elle n'est pas abstraite.

    C'est pour cela qu'elle n'est pas reportée.
    C'est ce que je dis ^^ Qu'elle soit dans une interface ou non, elle n'est pas reportée, puisque déjà définie dans la classe Object, ce qui est tout de même embêtant.

+ Répondre à la discussion
Cette discussion est résolue.

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