Frage

Ich versuche equals Methode für eine parametrisierte Klasse außer Kraft zu setzen.

@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;
}

Wie kann ich sicherstellen, dass <E> des other Objekt ist die gleiche wie this?

War es hilfreich?

Lösung

Sie können es tun, indem Sie einen Verweis auf Class<E> Typ beibehalten werden. Doch meiner Meinung nach, Gleichheit Tests sollten über die Werte sein, die Objekte darstellen, anstatt die konkreten Typen die Werte ausgedrückt bekommen .

Ein klassisches Beispiel dafür ist der Collections-API zum Beispiel. new ArrayList<String>().equals(new LinkedList<Object>()) kehrt true. Während diese völlig unterschiedliche Typen haben, stellen sie den gleichen Wert, nämlich „eine leere Sammlung“.

persönlich sollten zwei Tuples, die die gleichen Daten (z.B. ("a", "b")) stellen nicht gleich sein, denn eine vom Typ Tuple<String> ist, während der andere Tuple<Object> ist?

Andere Tipps

Durch Löschen können Sie nicht. Über das Beste, was Sie tun können, ist Speicher in dem Tupel-Klasse die Sie für den Tuple planen, in einem „java.lang.Class“ Feldelement zu halten. Dann könnten Sie diese Felder vergleichen, um sicherzustellen, dass die Tupel-Klasse die gleichen Typen hält.

Siehe auch dieses Thema anschauen: Was ist das Äquivalent des C ++ Pair in Java?

Es würde helfen, wenn Sie mehr über Ihre Klasse schreiben. Ich denke, das nicht markiert Besetzung und die Anzahl der Felder, die Sie gleichzusetzen bedeutet, sollte es Tuple nein?

sein

EDIT: Hier ist eine nützliche Klasse Pair ich regelmäßig nutzen (Sie können Ihre Tuple-Klasse anpassen, wenn nötig). Beachten Sie, ähnlich zu den Vorschlägen von anderen dieser Klasse können nur die enthaltenen Mitglieder die Frage der Gleichheit entscheiden. Ihr Anwendungsfall ist das, was bestimmen sollte, ob Gleichheit wirklich von der Art der enthaltenen Elemente basiert.

/**
 * 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

Ich lief in dieses Problem selbst, und in meinem -particular- Fall brauchte ich nicht den Typ E kennen.

Zum Beispiel:

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;
    }
}

In dem obigen Code, gibt es keine unkontrollierte Besetzung wegen Example<?> verwenden. Der Typ-Parameter Platzhalter ‚?‘ rettet den Tag.

Leider kann man dies nicht bei der Kompilierung tun; die Information ist verschwunden. Solche Folgen von Typ Löschung sind . Eine Alternative ist, den Parameter als Class Instanz zu speichern, und es dann später nachschlagen.

Da Generika werden bei der Kompilierung gelöscht , Sie im Grunde kann es nicht. Zur Laufzeit wird jeder Typ Parameter weg, und so weit wie die JVM betrifft, sie sind genau die gleichen in jeder Hinsicht.

Die Art und Weise um, dass zu arbeiten, ist ein Class Feld zu speichern, die die Art darstellt, und das Objekt mit dieser Art im Konstruktor erstellen.

Eine Probe Konstruktor:

public class Tuple < E > {

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

}

Sie können auch eine Fabrik verwendet werden:

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.
}

Die Vorschläge mit einem E Objekt scheinen ineffizient (das ist eine Menge von sinnlosen Verweisen auf einen Class Aufnahme-Speicher) und sinnlos für Ihr Problem einen Verweis auf Class der Art zu erhalten.

Es ist im allgemeinen nicht wahr, dass Foo<Bar> andFoo<Baz> ungleich sein sollte. Sie müssen also E nicht. Und Sie den Code geschrieben, Sie brauchen es nicht einmal zu kompilieren. Einfach Tuple<?> werfen, denn das ist wirklich alles wissen Sie über Tuple an diesem Punkt. Es kompiliert noch und alle.

Wenn Sie Tuples mit Daten von zwei völlig unterschiedliche Arten übergeben werden, werden nicht diejenigen Elemente equals werden, und Ihre Methode wird false zurückkehren, wie gewünscht. (Man hofft, -. Ist abhängig von diesen Typen Umsetzung equals sanely)

Off-topic - tun Sie erkennen, dass nach der Implementierung, Tuple (a0, a1) gleich Tuple (a1, a1)? Ich vermute, das ist nicht das, was Sie wollen ...

Ein-Thema, wie andere gesagt haben, macht das Löschen dieses unmöglich. Aber Sie sollten überdenken, warum diese wollen - Gleichheit Überprüfung geschieht erst zur Laufzeit und Generika sind nur Compiler-. Konzeptionell ein Variable hat allgemeine Parameter, sondern ein Objekt nicht. Wenn Sie also die Gleichheit der Objekte sind zu vergleichen, sind die allgemeinen Parameter nicht Sache überhaupt; Sie können keine entsprechenden Maßnahmen ergreifen ohnehin auf sie zur Laufzeit berechnet.

Objekt Gleichheit und allgemeine Parameter Mit- / Gegen Varianz sind zwei orthogonal Bedenken.

Ich bin mit den obigen Ausführungen, warum die Klasse E gleich zu sein brauchen? und wie wollen Sie Subklassen von E behandeln möchten?

Wie auch immer, da hier ein Codebeispiel, das Ihnen helfen kann:

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));
  }
}

Sie können anrufen t.getClass () der Klasse Informationen über die Art von T zu erhalten (vorausgesetzt, es ist nicht null, natürlich.)

Ich hoffe, das hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top