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 :

POO, généricité et equals (résultat étonnant)


Sujet :

avec Java

  1. #1
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2015
    Messages : 3
    Points : 1
    Points
    1
    Par défaut POO, généricité et equals (résultat étonnant)
    Salut à tous,
    Je viens de faire face à un résultat qui m'échappe, du coup, je viens vers vous dans l'espoir de comprendre le pourquoi du comment.
    En bref, j'essaye de coder une table de stockage (StorageTable) utilisant la généricité.
    Mon objet de test, et un objet Shape, comportant 3 dimensions (x,y,z), le equals est codé dessus (pour les 3dimensions) et fonctionne.

    Ma table de stockage correspond (en version courte à ceci) :
    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
    package model.storageTable;
    import java.util.ArrayList;
    import model.libItems.Shape;
     
    public class StorageTable<Type> {
    	private ArrayList<Type> stored;
     
    	public StorageTable() {
    		stored= new ArrayList<Type>();
    	}
     
    	public void add(Type value) {
    		stored.add(value);
    	}
     
    	public boolean test(Type toCheck, Type searched) {		
    		return searched.equals(toCheck);
    	}
    }
    Et voici mon main, (il est directement inclu dans la feuille précédente) :
    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
    	public static void main(String[] args) {
                    // On crée la table de stockage, et on la rempli de forme (k,k,k) de 0 à 9
    		StorageTable<Shape> s=new StorageTable<Shape>();
    		for (Integer k=0;k<10;k++) {
    			s.add(new Shape(k,k,k));
    		}
     
     
    		System.out.println("\n -------------------------------- \n");
                    //On effectue le test de 2 à 4, la forme a trouvée étant la (3,3,3), le résultat des autres correspond
     
                    Shape shape=new Shape(3,3,3);
     
    		for (int k=2; k<5;k++) {
    			System.out.print("Pour : "+k);
    			System.out.print("\t\tPar fonction : ");
    			System.out.println(s.test(s.stored.get(k),shape));
    			System.out.print("\t\tDirectement : ");
    			System.out.println(shape.equals(s.stored.get(k)));
    		}
     
    	}
    J'obtiens pour k = 2 et 4 : false que ce soit directement ou par fonction (ce qui est attendu).
    J'obtiens pour k = 3 : false par fonction, et true directement (je m'attendais à true, sachant que les 2 sont normalement bien equals).
    Ce qui me perturbe, c'est que les 2 font pour moi la même chose, ou presque.

    J'ai fait pas mal de tests, et c'est donc le problème que j'ai finalement isolé.
    Quelqu'un aurait une idée de quel en est la raison ?



    Merci d'avance !

    Edit : J'ai fait quelques tests supplémentaires : - ce n'est à priori pas un problème de classe dû à la généricité, getClass() me renvoie bien le même résultat.
    - j'obtiens le même phénomène, en remplaçant le ListArray<Type> directement par une instant de classe Type.
    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
    package model.storageTable;
    import model.libItems.Shape;
     
    public class Clone<Type> {
    	private Type clone;
     
    	public Clone(Type toClone){
    		clone=toClone;
    	}
     
    	public boolean test(Type toCheck,Type searched) {
    		return searched.equals(toCheck);
    	}
     
    	public static void main(String[] args) {
    		Shape s=new Shape(1,1,1);
    		Clone<Shape> c=new Clone<Shape>(new Shape(1,1,1));
    		System.out.println(s.equals(c.clone));
    		System.out.println(c.test(c.clone,s));
    	}
    }
    - Par contre, si j'utilise le même objet plutôt qu'un nouvel, (Clone<Shape> c=new Clone<Shape>(s); ), j'obtiens bien true aux 2.

  2. #2
    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 TheWiwi Voir le message
    Mon objet de test, et un objet Shape, comportant 3 dimensions (x,y,z), le equals est codé dessus (pour les 3dimensions) et fonctionne.
    Pourtant il y a de très forte chance que le problème viennent de là... et c'est le seul code que tu ne nous donne pas.

    A quoi ressemble ta classe Shape ?


    a++

  3. #3
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2015
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Mmmh, peut être, en fait ça m'étonnerait (vu que la fonction equals fonctionne), mais vu que justement je ne comprend pas le résultat.
    La voici, sans les getter et setter et fonctions non utilisées.

    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
    public class Shape {
    	private Integer length ;
    	private Integer width ;
    	private Integer height ;
     
    	public Shape(Integer length,Integer width, Integer height) {
    		this.length=length;
    		this.width=width;
    		this.height=height;
    	}
     
    	public String toString() {
    		return height+"mm height, "+width+"mm width, "+length+"mm length";
    	}
     
    	public boolean equals(Shape shape) {
    		return (width==shape.width && length==shape.length && height==shape.height);
    	}
    }
    Merci de ton aide.

  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
    Il y a deux problèmes dans ton code.

    • Premièrement tu utilises des Integer, donc tu dois gérer les nulls et utiliser equals() et non pas == qui se base sur l'instance et peut avoir un résultat erronée (new Integer(1).equals(1) retourne false)
    • Secondo, tu ne redéfinies pas la méthode equals(Object), mais tu la surcharges avec equals(Shape).
      Donc la méthode exécutée dépend du contexte d'appel.
      Dans la méthode test() c'est equals(Object) qui est appelée (puisqu'on ne connait pas le type exact de l'instance).
      Lors de l'appel direct c'est equals(Shape) qui est appelée... d'où le résultat différent.

      Il faut bien sûr redéfinir equals(Object) ! L'utilisation de l'annotation @Override permet d'éviter ce genre d'erreur.



    Perso je réécrirais la classe comme cela (en supposant qu'on n'a pas besoin d'Integer ni de valeur nulles :
    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
    public class Shape {
    	private int length ;
    	private int width ;
    	private int height ;
     
    	public Shape(int length, int width, int height) {
    		this.length=length;
    		this.width=width;
    		this.height=height;
    	}
     
    	@Override
    	public String toString() {
    		return height+"mm height, "+width+"mm width, "+length+"mm length";
    	}
     
    	@Override
    	public boolean equals(Object other) {
    		if (this==other) {
    			return true;
    		}
    		if (this instanceof Shape) {
    			Shape shape = (Shape) other;
    			return (width==shape.width && length==shape.length && height==shape.height);
    		}
    		return false;
    	}
    }


    Si tu as vraiment besoin des Integer alors cela donnerait ceci pour la méthode equals() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    	@Override
    	public boolean equals(Object other) {
    		if (this==other) {
    			return true;
    		}
    		if (this instanceof Shape) {
    			Shape shape = (Shape) other;
    			return Objects.equals(width, shape.width) && Objects.equals(length,shape.length) && Objects.equals(height,shape.height);
    		}
    		return false;
    	}


    a++

  5. #5
    Nouveau Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2015
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2015
    Messages : 3
    Points : 1
    Points
    1
    Par défaut
    Ha merci beaucoup !

    Tu m'as appris pas mal de choses sur le coup.
    Mon IDE grise les @.* , du coup j'ai bêtement cru que c'était juste un sorte de commentaire, du coup je les ai pas mis.
    C'est encore plus idiot, du fait que j'ai déjà du utiliser des trucs du style Junit ou Doctrine.

    Du coup, j'avais pas du tout compris la manière de redéfinir une fonction.

    L'explication sur le equals(Object), equals(Shape) est super claire aussi. Et ça me fait comprendre quelques trucs de plus la dessus (quelle est la fonction appelée avec la généricité.

    Effectivement, j'ai choisis le Integer pour avoir accès à null.

    J'ai 2 questions du coup.

    - > Il suffit que je redéfinisse equals avec @Override comme tu l'as montré pour toutes les classes et quand ça compilera, il accumulera toutes les nouvelles propriétés ?

    - > Pourquoi utilises-tu Object.equals(width,shape.width), plutôt que width.equals(shape.width) ? Vu que c'est plus long, je suppose qu'il y a une raison à ceci, non ?


    Merci beaucoup pour ton aide.

  6. #6
    Modérateur
    Avatar de joel.drigo
    Homme Profil pro
    Ingénieur R&D - Développeur Java
    Inscrit en
    Septembre 2009
    Messages
    12 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur R&D - Développeur Java
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2009
    Messages : 12 430
    Points : 29 131
    Points
    29 131
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par TheWiwi Voir le message
    - > Pourquoi utilises-tu Object.equals(width,shape.width), plutôt que width.equals(shape.width) ? Vu que c'est plus long, je suppose qu'il y a une raison à ceci, non ?
    Déjà pour éviter le NullPointerException si width est null, mais surtout d'écrire ((width==shape.width) || (width!=null && width.equals(shape.width)) qui est encore plus long !

    Citation Envoyé par TheWiwi Voir le message
    - > Il suffit que je redéfinisse equals avec @Override comme tu l'as montré pour toutes les classes et quand ça compilera, il accumulera toutes les nouvelles propriétés ?
    Que veux tu dire par "accumulera toutes les nouvelles propriétés".
    @Override permet simplement d'indiquer la méthode ainsi annotée redéfinit une méthode de la super classe. Le compilateur vérifie alors qu'il y a bien une méthode de signature compatible à redéfinir : si ce n'est pas le cas, la classe ne compile pas. Dans le cas de Shape, la méthode equals(Shape) n'existant pas dans Object, un @Override juste avant aurait empêcher la compilation t'alertant sur un problème potentiel. Mais si tu étends ta classe Shape (en laissant la méthode equals(Shape)), et que tu rédéfini la méthode equals(Shape) en mettant @Override, ça compilera sans problème.
    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
    31
    32
    public class Demo {
     
    	@Override // ne compile pas
    	public boolean equals(Demo test) {
    		return test==this;
    	}
     
    	@Override // ne compile pas
    	public Number truc() {
    		return null;
    	}
     
    	public static class DemoX extends Demo {
     
                    @Override // ne compile pas
    		public boolean equals(DemoX test) {
    			return super.equals(test);
    		}
     
    		@Override
    		public boolean equals(Demo test) {
    			return super.equals(test);
    		}
     
    		@Override
    		public Integer truc() {
    			return 42;
    		}
     
    	} 
     
    }
    Enlève les @Override // ne compile pas, tout compile.

Discussions similaires

  1. [PHP 5.2] preg_replace et accent : Résultat étonnant
    Par neojick dans le forum Langage
    Réponses: 9
    Dernier message: 27/04/2010, 13h32
  2. Réponses: 7
    Dernier message: 17/06/2008, 15h21
  3. Réponses: 1
    Dernier message: 03/02/2007, 19h02
  4. rewriting / Erreur d'URL.. un résultat étonnant
    Par Joe Le Mort dans le forum Dépannage et Assistance
    Réponses: 2
    Dernier message: 10/08/2006, 10h09

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