„Gleich“ Methode überschreibt: wie die Art des Parameters, um herauszufinden?
-
06-07-2019 - |
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
?
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 Tuple
s, 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
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
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 Tuple
s 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.
Mit Reflexion. http://tutorials.jenkov.com/java-reflection/generics.html