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 :

Question bête : égalité et comparateur


Sujet :

Langage Java

  1. #1
    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
    Par défaut Question bête : égalité et comparateur
    Salut,

    J'ai déjà rencontré ce problème plusieurs fois.

    Pour comparer des objets, on peut utiliser des Comparator<T,T> (qui a l'avantage sur Comparable<T> de pouvoir avoir plusieurs ordres différents selon les critères).

    Pourquoi il n'y a pas une interface similaire pour l'égalité?
    On a bien .equals(Object o)... Mais on n'a pas Equality<T,T>.

    C'est bien génant parfois...

    EDIT: c'est sûr on peut faire une classe qui est composée d'un T (un attribut de type T), et on redéfinit le .equals(Object)... Mais c'est moyen...

  2. #2
    Membre éprouvé
    Avatar de Janitrix
    Inscrit en
    Octobre 2005
    Messages
    3 391
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 3 391
    Par défaut
    Tu l'as trouvé où ton Comparator<T, T> ? Moi je vois dans java.util Interface Comparator<T>. Et une méthode :
    equals(Object obj)
    Indicates whether some other object is "equal to" this comparator.
    C'est pas ce que tu veux ?

  3. #3
    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
    Par défaut
    Citation Envoyé par Janitrix
    Tu l'as trouvé où ton Comparator<T, T> ? Moi je vois dans java.util Interface Comparator<T>. Et une méthode :
    C'est pas ce que tu veux ?
    Effectivement c'est Comparator<T> (évidemment <T, T> ça n'a pas de sens).

    Non c'est pas cette méthode qu'il faut (elle est faite ici pour tester l'égalité des comparators)

  4. #4
    Membre éprouvé
    Avatar de Janitrix
    Inscrit en
    Octobre 2005
    Messages
    3 391
    Détails du profil
    Informations forums :
    Inscription : Octobre 2005
    Messages : 3 391
    Par défaut
    Arf désolé j'ai pas pris le temps de lire la description de la méthode. Sinon, tu peux toujours l'implémenter toi même, ça doit pas être très dure . Juste, pour faire un algorithme de comparaison efficace mais là tu es bien aidé par Java. Un peu d'aide ?

  5. #5
    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
    Par défaut
    Pour montrer le pattern auquel j'avais pensé:
    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
    public class ABC {
     
        private int state;
     
        public Object otherEqualizer() {
            return new Object() {
     
                @Override
                public boolean equals(Object other) {
                    return other != null && other instanceof ABC && state == ((ABC) other).state;
                }
            };
        }
     
        @Override
        public boolean equals(Object other) {
            return false;
        }
     
    }
    Je trouve ça moins propre qu'un comparator... (mais bon on ne peut pas non plus faire notre interface nous-même, car il faudrait avoir un argument dans les collections pour par exemple la méthode remove)

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

    Informations forums :
    Inscription : Juillet 2006
    Messages : 548
    Par défaut
    Le comparator renvoie 0 pour deux objets "égaux", ça fait l'affaire non ?

  7. #7
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par ®om
    Pour montrer le pattern auquel j'avais pensé
    Je ne comprend pas vraiment l'intérêt de cela... tu pourrais expliquer ton objectif ???

    a++

  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
    Par défaut
    Par exemple, j'ai une classe Transition.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Transition
    ----------
    node1: Node
    node2: Node
    cost: int
    En fait j'aurais besoin de 2 méthodes equals.
    Une (celle par défaut) qui renvoie true si les 2 transitions ont les mêmes noeuds extrêmité, et une autre qui en plus prend en compte le coût.

    Par exemple (en langage informel):
    Transition 1 = { node1, node2, 5 }
    Transition 2 = { node2, node1, 10 }

    J'ai 2 fonctions d'égalité, une qui regarde si les ensemble contenant les 2 noeuds sont égaux, ici TRUE, et l'autre qui regarde si à la fois les ensembles sont égaux mais aussi le coût, ici FALSE...

    Tout comme on fait plusieurs fonctions de comparaison avec Comparator, je voudrais faire plusieurs fonctions d'égalité.

  9. #9
    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
    Par défaut
    Citation Envoyé par the-gtm
    Le comparator renvoie 0 pour deux objets "égaux", ça fait l'affaire non ?
    Tout n'est pas Comparable... et la méthode remove de Collection ne se base pas sur Comparator (en tout cas pas pour toutes les implémentations).

  10. #10
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    En fait tu voudrais avoir plus type d'égalité différentes... mais cela casse un peu les spécifications du equals()...

    En fait tu voudrais un moyen de filtrer des objets selon différents critères, et utiliser ses propres implémentations de remove(), par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public interface Filter<T> {
    	public boolean accept(T other);
    }
    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
    public class CollectionsUtils {
     
    	public static <T> boolean removeFirst(Collection<T> c, Filter<T> filter) {
    		Iterator<T> iterator = c.iterator();
    		T element;
    		while ( (element=iterator.next()) != null) {
    			if (filter.accept(element)) {
    				iterator.remove();
    				return true;
    			}
    		}
    		return false;
    	}
     
     
     
    	public static <T> boolean removeAll(Collection<T> c, Filter<T> filter) {
    		boolean removed = false;
    		Iterator<T> iterator = c.iterator();
    		T element;
    		while ( (element=iterator.next()) != null) {
    			if (filter.accept(element)) {
    				iterator.remove();
    				removed = true;
    			}
    		}
    		return removed;
    	}
     
    }
    Si je me souviens bien un mécanisme similaire existe dans les Jakarta Commons Collection...


    a++

  11. #11
    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
    Par défaut
    En fait, on peut généraliser (ou le spécialiser, car en fait il ne faut pas forcément n fonctions d'égalités mais seulement 2) le problème, par analogie aux EJB.

    Un objet a une partie clé, une partie valeur.
    Dans mon exemple précédent, la clé c'est l'ensemble des 2 noeuds, et la valeur est le coût.

    Il faudrait avoir une fonction d'égalité de clé (et pouvoir dans une collection récupérer un objet à partir de sa clé), et une fonction d'égalité totale (clé + valeur).

    Bien sûr on peut faire ça si l'on met en place un serveur d'application, mais c'est un peu dommage d'utiliser cela pour simplement des fonctions d'égalités...

    Certes, le couple (clé,valeur) ça fait penser à Map, mais on n'a pas forcément envie d'exploser nos objets et de les ranger forcément dans des Map.

  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
    Par défaut
    J'ai donc pensé à ce pattern pour avoir une partie clé et une partie valeur:
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    public class AnObject {
     
        public static class PK {
     
            //attributs de la primarykey
            private Object attribut1;
            private String attribut2;
            //...
     
            public PK(Object attribut1, String attribut2) {
                this.attribut1 = attribut1;
                this.attribut2 = attribut2;
            }
     
            public Object getAttribut1() {
                return attribut1;
            }
     
            public String getAttribut2() {
                return attribut2;
            }
     
            @Override public boolean equals(Object other) {
                if(other == null) {
                    return false;
                }
                if(other instanceof PK) {
                    PK pk = (PK) other;
                    return attribut1.equals(pk.attribut1) && attribut2.equals(pk.attribut2);
                } else if(other instanceof AnObject) {
                    return equals(((AnObject)other).getPK());
                }
                return false;
            }
     
            @Override public int hashCode() {
                //calculer le hashCode en adéquation avec equals
                return 0; //à calculer
            }
        }
     
        //partie clé
        private PK pk;
     
        //attributs de la partie valeur
        private int value;
        //...
     
        public AnObject(Object o, String s, int val) {
            pk = new PK(o,s);
            value = val;
        }
     
        public PK getPK() {
            return pk;
        }
     
        public Object getAttribut1() {
            return pk.getAttribut1();
        }
     
        public String getAttribut2() {
            return pk.getAttribut2();
        }
     
        public int getValue() {
            return value;
        }
     
        @Override public boolean equals(Object other) {
            //retourne true lorsque à la fois les pk sont égales et les valeurs sont égales
            if(other == null || !(other instanceof AnObject)) {
                return false;
            }
            AnObject o = (AnObject)other;
            return pk.equals(o.pk) && value == value;
        }
     
        @Override public int hashCode() {
            //calculer le hashCode en adéquation avec equals
            return 0; //à calculer
        }
     
    }
    C'est vraiment lourd pour simplement créer une classe...

    L'avantage c'est qu'on peut utiliser la primary key pour supprimer un objet de la liste. L'inconvénient c'est qu'on n'a pas le .get(Object) sur les collections.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class TestEqualizer {
     
        public static void main(String... args) {
            Collection<AnObject> col = new ArrayList<AnObject>();
            col.add(new AnObject("abc","def",4));
            col.add(new AnObject("ghi","jkl",8));
            col.add(new AnObject("mno","pqr",12));
            col.remove(new AnObject.PK("abc","def"));
            System.out.println(col.size()); //retourne 2
            //ce qu'il manque encore, par analogie au getByPrimaryKey de EJB
            //AnObject o = col.get(new AnObject.PK("ghi,"jkl"));
        }
     
    }
    Les EJB apportent ce concept de primary key, qui évidemment vient de la base de données, mais qu'il serait intéressant d'avoir également en orienté objet. Malheureusement Java n'apporte pas ce concept

    Qu'en pensez-vous?

  13. #13
    Expert éminent
    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
    Billets dans le blog
    1
    Par défaut
    Quelques remarques :
    • Dans la méthode equals() tu n'as pas besoin de vérifier les null car c'est géré par instanceof. Par contre tu peux comparer avec this pour éviter des comparaisons inutiles :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      @Override public boolean equals(Object other) {
                  if (this==other) {
                      return true;
                  }
                  if(other instanceof PK) {
                      PK pk = (PK) other;
                      return attribut1.equals(pk.attribut1) && attribut2.equals(pk.attribut2);
                  } else if(other instanceof AnObject) {
                      return equals(((AnObject)other).getPK());
                  }
                  return false;
              }
    • Enfin il peut y avoir un effet de bord si les hashCode ne sont pas cohérent entre AnObject et PK, car les implémentations des méthodes des collections peuvent utiliser hashCode() pour améliorer leurs algorithmes et donc éviter d'appeler equals() si les hashCode() ne sont pas égaux... Il faut donc que le hashCode() de AnObject soit identique à sa clef, donc j'aurais plutôt fait ceci :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
          @Override public int hashCode() {
              // hascode de la clef :
          	return this.pk.hashCode();
          }
    • Enfin, cela casse un peu les spécifications de equals() puisque cela casse la symétrie mais ce n'est pas bien grave :
      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.




    Citation Envoyé par ®om
    L'avantage c'est qu'on peut utiliser la primary key pour supprimer un objet de la liste. L'inconvénient c'est qu'on n'a pas le .get(Object) sur les collections.
    Si tu veux accéder à un objet via son identifiant, c'est typiquement que tu as besoin d'une Map



    a++

Discussions similaires

  1. Question bête (PHP veux se télécharger)
    Par Nicos77 dans le forum Langage
    Réponses: 12
    Dernier message: 12/10/2005, 15h21
  2. Réponses: 7
    Dernier message: 05/10/2005, 11h29
  3. [VBA][Excel]Petite question bête !
    Par Mugette dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 20/09/2005, 15h36
  4. [MFC] Question bête sur les CListBox
    Par gwendo dans le forum MFC
    Réponses: 1
    Dernier message: 10/08/2005, 16h43
  5. Numéro auto ===== Question bête
    Par Nicos77 dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 16/06/2003, 13h04

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