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 :

instanceof c'est mauvais?


Sujet :

Langage Java

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    55
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2006
    Messages : 55
    Points : 44
    Points
    44
    Par défaut instanceof c'est mauvais?
    Bonjour,
    Je dois utiliser instanceof quelque part dans mes classes mais tout le monde me dit que instanceof est une mauvaise construction. Entre autres parce que dans un design qui utilise l'héritage, si on rajoute une classe, on doit changer des choses dans les autres classes qui héritent de la même classe. Mais sinon je ne comprends pas très bien pourquoi ne pas l'utiliser. De plus, connaissez-vous une alternative "propre"?
    Merci d'avance

  2. #2
    Membre averti Avatar de let_me_in
    Inscrit en
    Mai 2005
    Messages
    441
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 441
    Points : 437
    Points
    437
    Par défaut
    Entre autres parce que dans un design qui utilise l'héritage, si on rajoute une classe, on doit changer des choses dans les autres classes qui héritent de la même classe
    je n'ai rien compris la, mais ce que je peut te dire c'est le suivant:
    si une classe B herite de A, et si tu as un objet 'a' alors les deux proposistions suivantes sont juste :
    pour l'autre alternative tu as peut etre le
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tonObjet.getClass().getName();
    voici un exemple illustrant tout ce que j'ai dis:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    class A{
    int a;
    public A(){
    }
     
    }
     
    public class Test extends A{
     
    	public Test(){
    		if (this instanceof Test)System.out.println("test");
    		if (this instanceof A)System.out.println("A");
    		System.out.println(this.getClass().getName());
    	}
     
    	/**
             * @param args
             */
     
     
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		new Test();
    	}
     
    }
    hope this helps.
    a+
    qui dit Dieu n'existe pas dis que les programmes tournent sans processeur.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    55
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2006
    Messages : 55
    Points : 44
    Points
    44
    Par défaut
    Oui, je comprend comment on utilise l'instanceof. Mais on m'a toujours dit que ce n'est jamais bon d'utiliser instanceof et qu'il vaut mieux l'éviter. Mais des fois il me semble inévitable. C'est pour ça que je demande si il existe une autre alternative.

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Mai 2007
    Messages : 6
    Points : 6
    Points
    6
    Par défaut Une alternative
    Salut,

    Effectivement il en existe une . Le POLYMORPHISME. notamment le principe de résolution dynamique des liens . dans un model d'héritage comme celui proposé plus haut , un objet a construit à partir de la classe B sous classe de A , est aussi un objet de la classe A. cet objet bénéficie donc des méthodes de la classe A sans que tu n 'aie besoin de faire un "instanceof" .
    S'il t arrive de redefinir dans B des méthodes qui sont dejà definies dans A , alors ce sont celles là qui seront executées , et non celles de A et cela sans besoin de test '' instanceof'.'

    En esperant que cela repond à ta question.
    A+

  5. #5
    Membre émérite
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Points : 2 582
    Points
    2 582
    Par défaut
    Perso je continue à l'utiliser, car je trouve que les alternatives pure objet sont souvent moins claires à la lecture, plus difficiles à comprendre et à maintenir, du moins en java. J'ai essayé 150 trucs, je n'en ai pas trouvé qui soyent vraiment confortables.

    Je pense que le fond du problème est qu'il ne faut pas s'obliger à utiliser le polymorphisme, mais, comme le reste, de ne l'utiliser que lorsqu'il est adapté. Lorsque, au fur et à mesure des évolutions du code, on trouve le polymorphisme adapté, alors les instanceofs s'effacent d'eux mêmes, et le code reste clair.

    Mais se dire Je mets pas de instanceof sinon tout le monde va voir que j'y connais rien au polymorphisme est une très mauvaise approche.

    Le polymorphisme est un excellent outil, du moment qu'il est en phase avec le domaine qu'il exprime. Sinon les décalages entre formalisme du code et réalité obligent à multiplier les interfaces, les interfaces d'implémentation d'interfaces, les abstractions de builder de factories, et c'est la catastrophe. Le gros défaut du polymorphisme est qu'il n'est pas évident de trouver le bon réglage pour une application ou un domaine donné. Cela ne vient que petit à petit, avec de l'expérience et en discutant avec les utilisateurs ou spécialistes.

    Donc, moralité selon moi : utilise le instanceof et le polymorphisme.
    Mieux que Google, utilisez Sur Java spécialisé sur la plate-forme java !
    Pour réaliser vos applications Java dans le cadre de prestations, forfait, conseil, contactez-moi en message privé.

  6. #6
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Citation Envoyé par pongping
    Bonjour,
    Je dois utiliser instanceof quelque part dans mes classes mais tout le monde me dit que instanceof est une mauvaise construction. Entre autres parce que dans un design qui utilise l'héritage, si on rajoute une classe, on doit changer des choses dans les autres classes qui héritent de la même classe. Mais sinon je ne comprends pas très bien pourquoi ne pas l'utiliser. De plus, connaissez-vous une alternative "propre"?
    Merci d'avance
    Un cas typique où il faut éviter le instanceof, c'est ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    if(o instanceof A) {
        ((A)o).method();
    } else if(o instanceof B) {
        ((B)o).method();
    } //...
    Parfois instanceof se justifie.
    Par exemple, en ce moment pour les cours on doit faire un compilateur Java (sans optimisations). Une approche pour différencier les variables des attributs était que Attribut extends Variable, et que Attribut ait, en plus des attributs de Variable, un attribut "visibility" (private, public...).
    Lorsqu'on accède à un objet Variable (pour appeler une méthode dessus par exemple), il faut qu'on teste si "on a le droit de le faire", c'est-à-dire si la variable est accessible. Pour cela on peut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(!(variable instanceof Attribut) || ((Attribut)variable).isPublic())
    Ce n'est finalement pas l'approche que l'on a retenu, mais il me semble que celle-ci n'est pas mauvaise.

    Si quelqu'un trouve qu'elle n'est pas bonne, merci de répondre et de dire pourquoi, ça m'intéresse

    Pour finir, il y a des endroits où il FAUT toujours utiliser instanceof:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Override
    public boolean equals(Object o) {
        if(!(o instance MaClass) {
            return false;
        }
        return name.equals(o.name);
    }

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Points : 635
    Points
    635
    Par défaut
    Lorsqu'on accède à un objet Variable (pour appeler une méthode dessus par exemple), il faut qu'on teste si "on a le droit de le faire", c'est-à-dire si la variable est accessible. Pour cela on peut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(!(variable instanceof Attribut) || ((Attribut)variable).isPublic())
    Ce n'est finalement pas l'approche que l'on a retenu, mais il me semble que celle-ci n'est pas mauvaise.

    Si quelqu'un trouve qu'elle n'est pas bonne, merci de répondre et de dire pourquoi, ça m'intéresse
    Personnellement j'aurai fait ça comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (variable.isVisible(Visibility.PUBLIC))
    Avec isVisible qui renvoie toujours true pour une variable et qui est surchargée dans Attribut pour faire la verification.

  8. #8
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Citation Envoyé par the-gtm
    Personnellement j'aurai fait ça comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (variable.isVisible(Visibility.PUBLIC))
    Avec isVisible qui renvoie toujours true pour une variable et qui est surchargée dans Attribut pour faire la verification.
    Je trouve ça plus simple, mais moins propre.
    Car pour une variable, il n'y a pas la notion de visibilité...

    (même si c'est en gros la solution que l'on a retenu)

  9. #9
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Citation Envoyé par ®om
    JCar pour une variable, il n'y a pas la notion de visibilité...

    Quand on a quelque chose du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public void machin()
    {
     int i = 1;
     truc();
    }
     
    public void truc()
    {
     
    }
    La variable i qui se trouve dans la table des symboles devient en quelque sort "non visible". Mais maintenant, je ne sais pas comment tu as géré ta table des symboles... Parce que pour être efficace, ça la fout peut être mal de reparcourir toutes les variables pour les mettre en "non visible" Le compilateur que j'avais fait été dans un langage plus simple, et je n'avais pas eu ce problème en tout cas.
    Je ne répondrai à aucune question technique en privé

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    55
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : Suisse

    Informations forums :
    Inscription : Octobre 2006
    Messages : 55
    Points : 44
    Points
    44
    Par défaut
    Merci pour toutes ces réponses. Dans mon projet j'utilise beaucoup le polymorphisme mais j'étais tombé sur un problème ou le polymorphisme n'était pas possible (sauf si il fallait implémenter des méthodes vides dans certaines classes mais ceci n'est pas très beau non plus)... Je vais donc quand même utiliser instanceof.

  11. #11
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Citation Envoyé par pongping
    (sauf si il fallait implémenter des méthodes vides dans certaines classes mais ceci n'est pas très beau non plus)...
    Pourquoi ne pas faire des classes abstraites dans ce cas ? C'est justement fait quand des méthodes n'ont pas à être implémenté dans la classe mère.
    Je ne répondrai à aucune question technique en privé

  12. #12
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    @millie, a priori le cas que tu décris ne posera pas de problème, mais bon je te dirai quand on en sera là

    @pongping, peux-tu nous décrire le cas où tu penses avoir besoin du instanceof?

  13. #13
    Membre régulier
    Inscrit en
    Octobre 2006
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 108
    Points : 118
    Points
    118
    Par défaut
    Citation Envoyé par ®om
    Pour finir, il y a des endroits où il FAUT toujours utiliser instanceof:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Override
    public boolean equals(Object o) {
        if(!(o instance MaClass) {
            return false;
        }
        return name.equals(o.name);
    }
    Pas tout à fait d'accord sur ce point
    Pour moi, une bonne méthode equals n'utilise pas instanceof. Il faut aussi vérifier que o est de la même classe que l'objet. Sinon, on risque d'obtenir des cas où :
    - a.equals(b) est true
    - b.equals(a) est false
    si b est d'une classe dérivée de celle de a.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Override
    public boolean equals(Object o) {
        if ((o == null) || (o.getClass() != getClass())) {
            return false;
        }
        return name.equals(o.name);
    }

  14. #14
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    Pour moi, une bonne méthode equals n'utilise pas instanceof. Il faut aussi vérifier que o n'est pas une instance d'une classe dérivée de MaClass.
    Je ne vois pas le problème si tu redéfinis equal pour chaque classe fille.

    Par exemple, dans le code source de Java, pour la classe Rectangle qui hérite de Rectangle2D, il redéfinisse equals :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public boolean equals(Object obj) {
    	if (obj instanceof Rectangle) {
    	    Rectangle r = (Rectangle)obj;
    	    return ((x == r.x) &&
    		    (y == r.y) &&
    		    (width == r.width) &&
    		    (height == r.height));
    	}
    	return super.equals(obj);
    }
    Je ne répondrai à aucune question technique en privé

  15. #15
    Membre régulier
    Inscrit en
    Octobre 2006
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 108
    Points : 118
    Points
    118
    Par défaut
    Simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    class MaClass {
      String name;
     
      @Override
      public boolean equals(Object o) {
        if(!(o instance MaClass) {
            return false;
        }
        return name.equals(o.name);
    }
     
    class MaClass2 extends MaClass {
      String name2;
     
      @Override
      public boolean equals(Object o) {
        if(!(o instance MaClass) {
            return false;
        }
        if (!name2.equals(o.name2)) {
            return false;
        }
        return super.equals(o);
    }
    Avec ce code, si tu as :
    a = new MaClass('x');
    b = new MaClass2('x', 'y');

    Alors
    a.equals(b) est true
    b.equals(a) est false

    PS: Pour Rectangle, si tu ne la dérives pas, c'est bon (car Rectangle2D est abstract), mais c'est pas propre. Si tu fais des tests avec Rectangle et DefaultCaret, tu pourras voir des cas bizarres

  16. #16
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    Citation Envoyé par NicoV
    Pas tout à fait d'accord sur ce point
    Pour moi, une bonne méthode equals n'utilise pas instanceof. Il faut aussi vérifier que o est de la même classe que l'objet. Sinon, on risque d'obtenir des cas où :
    - a.equals(b) est true
    - b.equals(a) est false
    si b est d'une classe dérivée de celle de a.
    Pourquoi je pense qu'il faut utiliser instanceof et non getClass():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    class A {
        private String name;
        A(String name) {
            this.name = name;
        }
        @Override
        public boolean equals(Object o) {
    //    	if(!(o instanceof A)) {
            if(getClass() != o.getClass()) {
            	return false;
            }
            return name.equals(((A)o).name);
        }
    }
     
    class B extends A {
    	B(String name) {
    		super(name);
    	}
    }
     
    public class TestEquals {
     
    	public static void main(String... args) {
    		A a1 = new B("abc");
    		A a2 = new A("abc");
    		System.out.println(a1.equals(a2));
    	}
     
    }
    alors qu'on a définit que 2 objets A étaient égaux ssi ils avaient le même nom.

    Tu peux de toute façon obtenir des cas où equals n'est pas symétrique, le plus simple étant de rentre la relation anti-symétrique (et donc une relation d'ordre), et ceci que tu testes avec instanceof ou getClass().
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class C {
    	private int i;
    	@Override
    	public boolean equals(Object o) {
    		return i > ((C)o).i;
    	}
    }
    Enfin, concernant ton dernier exemple, je ne sais pas ce que tu as essayé de montrer, mais de toute façon il te manque les cast, donc il ne peut pas compiler. Et pour pouvoir les faire (les cast) de façon sûre, il faut tester o instanceof MaClass2 et non o instance Maclass dans MaClass2. Donc on ne peut pas conclure grand chose de ce test...

  17. #17
    Membre régulier
    Inscrit en
    Octobre 2006
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 108
    Points : 118
    Points
    118
    Par défaut
    La javadoc de Object.equals() :
    It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
    Donc, oui pour moi, il faut normalement que equals() soit symétrique et donc ne pas utiliser instanceof sauf dans des cas particuliers.

    En règle général, j'ai l'impression qu'un objet d'une classe dérivée ne doit pas être considéré égal à une objet d'une classe de base.

    PS: Pour mon exemple, je n'ai pas essayé de le compiler et donc oui il manque des cast mais c'était pour présenter une explication (d'ailleurs, il manque le même cast dans ton exemple initial ), et j'ai fait un copier/coller dans le 2e equals d'ou le MaClass ou lieu de MaClass2.

  18. #18
    Membre régulier
    Inscrit en
    Octobre 2006
    Messages
    108
    Détails du profil
    Informations forums :
    Inscription : Octobre 2006
    Messages : 108
    Points : 118
    Points
    118
    Par défaut
    Pour une explication détaillée sur l'intérêt d'utiliser getClass() au lieu de instanceof, un article pas mal: http://www.geocities.com/technofundo...equalhash.html

    ou encore dans Effective Java chez Sun:
    http://java.sun.com/developer/Books/...a/Chapter3.pdf

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Broken - violates symmetry!
    public boolean equals(Object o) {
      if (o instanceof CaseInsensitiveString)
        return s.equalsIgnoreCase(
          ((CaseInsensitiveString)o).s);
      if (o instanceof String) // One-way interoperability!
        return s.equalsIgnoreCase((String)o);
      return false;
    }

  19. #19
    Membre expert
    Avatar de ®om
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    2 815
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 815
    Points : 3 080
    Points
    3 080
    Par défaut
    OK c'est vrai qu'il y a une faille avec le instanceof...

    Merci

  20. #20
    Rédacteur

    Avatar de millie
    Profil pro
    Inscrit en
    Juin 2006
    Messages
    7 015
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2006
    Messages : 7 015
    Points : 9 818
    Points
    9 818
    Par défaut
    At this point, p1.equals(p2) and p2.equals(p3) return true, while
    p1.equals(p3) returns false, a clear violation of transitivity. The first two comparisons are “color-blind,” while the third takes color into account.

    So what’s the solution? It turns out that this is a fundamental problem of
    equivalence relations in object-oriented languages. There is simply no way to
    extend an instantiable class and add an aspect while preserving the equals
    contract
    .
    Je ne répondrai à aucune question technique en privé

Discussions similaires

  1. Réponses: 1
    Dernier message: 28/05/2010, 11h39
  2. Coef et position, mauvais positionnement, est ce important ?
    Par alicia1984 dans le forum Droit du travail
    Réponses: 2
    Dernier message: 12/03/2010, 21h02
  3. instanceof ou mauvais polymorphisme ?
    Par Djakisback dans le forum Langage
    Réponses: 45
    Dernier message: 12/11/2007, 17h18
  4. [W3C] Les tableaux c'est si mauvais que ca ?
    Par ShinJava dans le forum Balisage (X)HTML et validation W3C
    Réponses: 7
    Dernier message: 03/03/2006, 14h17

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