Question

J'essaie de remplacer la méthode est égale à pour une classe paramétrée.

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Tuple))
        return false;

    Tuple<E> other = (Tuple<E>) obj; //unchecked cast
    if (!a0.equals(other.a0) && !a0.equals(other.a1)) {
        return false;
    }
    if (!a1.equals(other.a1) && !a1.equals(other.a0)) {
        return false;
    }

    return true;
}

Comment puis-je m'assurer que < E > de l'objet other est identique à this ?

Était-ce utile?

La solution

Vous pouvez le faire en conservant une référence au type Classe < E > . Cependant, à mon avis, les tests d’égalité devraient porter sur les valeurs représentées par les objets plutôt que sur les types concrets exprimés par les valeurs .

Un exemple classique est l’API de collections, par exemple. new ArrayList < Chaîne > (). égal à (new LinkedList < Objet > ()) renvoie true . Bien que ceux-ci aient des types complètement différents, ils représentent la même valeur, à savoir "une collection vide".

Personnellement, deux tuple représentant les mêmes données (par exemple, ("a", "b") ) ne sont pas égaux, car l'un est de tapez Tuple < Chaîne > tandis que l'autre est Tuple < Objet > ?

Autres conseils

En raison de l'effacement, vous ne pouvez pas. Le mieux que vous puissiez faire est de stocker dans la classe de tuple le type que vous souhaitez que le tuple contienne dans un "java.lang.Class". membre de terrain. Vous pouvez ensuite comparer ces champs pour vous assurer que la classe de tuple contient les mêmes types.

Voir aussi ce fil: Quel est l'équivalent de la paire C ++ < L , R > en Java?

Cela aiderait si vous publiez plus d'informations sur votre classe. Je pense que la distribution non contrôlée et le nombre de champs que vous assimilez signifient qu'il devrait s'agir de Tuple < E, F > non?

EDIT: voici une classe Pair que j’utilise régulièrement (vous pouvez adapter votre classe de Tuple si nécessaire). Remarque, similaire aux suggestions d'autres personnes, cette classe laisse simplement les membres contenus décider de la question de l'égalité. Votre cas d'utilisation est ce qui devrait déterminer si l'égalité est vraiment basée sur le type des membres contenus.

/**
 * Adapted from http://forums.sun.com/thread.jspa?threadID=5132045
 * 
 * 
 * @author Tim Harsch
 *
 * @param <L>
 * @param <R>
 */
public class Pair<L, R> {

    private final L left;
    private final R right;

    public R getRight() {
        return right;
    } // end getter

    public L getLeft() {
        return left;
    } // end getter

    public Pair(final L left, final R right) {
        this.left = left;
        this.right = right;
    } // end constructor

    public static <A, B> Pair<A, B> create(A left, B right) {
        return new Pair<A, B>(left, right);
    } // end factory method

    @Override
    public final boolean equals(Object o) {
        if (!(o instanceof Pair<?,?>))
            return false;

        final Pair<?, ?> other = (Pair<?, ?>) o;
        return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight());
    } // end method

    public static final boolean equal(Object o1, Object o2) {
        if (o1 == null) {
            return o2 == null;
        }
        return o1.equals(o2);
    } // end method

    @Override
    public int hashCode() {
        int hLeft = getLeft() == null ? 0 : getLeft().hashCode();
        int hRight = getRight() == null ? 0 : getRight().hashCode();

        return hLeft + (37 * hRight);
    } // end method

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('<');
        if( left == null ) {
            sb.append("null");
        } else {
            sb.append(left.toString());
        } // end if
        sb.append(',');
        if( right == null ) {
            sb.append("null");
        } else {
            sb.append(right.toString());
        } // end if
        sb.append('>');
        return sb.toString();
    } // end method
} // end class

Je viens de rencontrer ce problème moi-même et, dans mon cas particulier, je n'ai pas besoin de connaître le type E.

Par exemple:

public class Example<E> {
    E value;

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Example<?> other = (Example<?>) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }
}

Dans le code ci-dessus, il n'y a pas de conversion non contrôlée à cause de l'utilisation de Exemple <? > . Le paramètre de type wildcard '?' sauve la journée.

Malheureusement, vous ne pouvez pas faire cela au moment de la compilation; l'information est partie. Telles sont les conséquences de l'effacement du type . Une autre solution consiste à stocker le paramètre en tant qu'instance Class , puis à le rechercher ultérieurement.

Comme les les génériques ont été effacés lors de la compilation , vous fondamentalement ne peut pas. Au moment de l'exécution, tous les paramètres de type ont disparu et, en ce qui concerne la machine virtuelle Java, ils sont exactement les mêmes à tous égards.

Pour contourner ce problème, vous devez stocker un champ Class qui représente le type et créer l'objet avec ce type dans le constructeur.

Un exemple de constructeur:

public class Tuple < E > {

    public Tuple(Class<E> c) {
        //store the class
    }

}

Ou vous pouvez utiliser une usine:

public static <E> Tuple <E> getTuple(Class<E> type) {
    // Create and return the tuple, 
    // just store that type variable in it 
    // for future use in equals.
}

Les suggestions de conserver une référence au type de E avec un objet Class semblent inefficaces (c’est beaucoup de références inutiles à Classe occupant de la mémoire) et inutile pour votre problème.

Il n'est généralement pas vrai que Foo < Bar > et Foo < Baz > soient inégaux. Donc, vous n'avez pas besoin de E . Et, dans le code que vous avez écrit, vous n'avez même pas besoin de le compiler. Transformez simplement en Tuple <? & Gt; , car c’est tout ce que vous savez sur Tuple à ce stade. Il compile toujours et tout.

Si vous êtes passé Tuple avec des données de deux types très différents, ces éléments ne seront pas égaux et votre méthode retournera false , comme vous le souhaitez. (On espère - cela dépend de ces types qui implémentent est égal à sainement.)

Hors sujet - vous rendez-vous compte que selon votre implémentation, Tuple (a0, a1) est égal à Tuple (a1, a1)? Je soupçonne que ce n'est pas ce que vous voulez ...

Sur le sujet, comme d’autres l’ont dit, l’effacement rend cela impossible. Toutefois, vous devez reconsidérer la raison de votre choix: la vérification de l’égalité n’est effectuée qu’au moment de l’exécution et les médicaments génériques ne sont qu’une compilation . Conceptuellement, une variable a des paramètres génériques, mais pas un objet . Ainsi, lorsque vous comparez l'égalité des objets, les paramètres génériques n'ont aucune importance. de toute façon, vous ne pouvez prendre aucune mesure appropriée en fonction de ces dernières au moment de l’exécution.

L’égalité d’objet et le paramètre générique co- / contre-variance constituent deux préoccupations orthogonales.

Je suis d’accord avec les commentaires ci-dessus, pourquoi la classe E doit-elle être égale? et comment voulez-vous traiter les sous-classes de E?

Quoi qu'il en soit, étant donné qu'il s'agit d'un exemple de code susceptible de vous aider:

public class Example<T> {

  T t;

  public Example(T t) {
    this.t = t;
  }

  public static void main(String[] args) {
    final String s = "string";
    final Integer i = 1;
    final Number n = 1;

    final Example<String> exampleString = new Example<String>(s);
    final Example<Integer> exampleInteger = new Example<Integer>(i);
    final Example<Number> exampleNumber = new Example<Number>(n);

    System.out.println("exampleString subclass "  + exampleString.t.getClass());
    System.out.println("exmapleIntger subclass " + exampleInteger.t.getClass());
    System.out.println("exmapleNumber subclass " + exampleNumber.t.getClass());
    System.out.println("Integer equals Number = " + 
        exampleInteger.t.equals(exampleNumber.t));
  }
}

Vous pouvez appeler t.getClass () pour obtenir des informations sur la classe concernant le type de T (en supposant qu'il ne soit pas nul, bien sûr.)

J'espère que cela vous aidera.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top