450 Stimmen

Was sind die Gründe, warum Map.get(Object key) nicht (vollständig) generisch ist?

Was sind die Gründe für die Entscheidung, keine vollständig generische get-Methode zu verwenden? in der Schnittstelle von java.util.Map<K, V> .

Um die Frage zu klären, lautet die Signatur der Methode

V get(Object key)

anstelle von

V get(K key)

und ich frage mich, warum (dasselbe gilt für remove, containsKey, containsValue ).

285voto

newacct Punkte 114757

Wie bereits von anderen erwähnt, ist der Grund dafür get() usw. ist nicht generisch, da der Schlüssel des abgerufenen Eintrags nicht vom gleichen Typ sein muss wie das Objekt, das Sie an get() Die Spezifikation der Methode verlangt nur, dass sie gleich sind. Dies ergibt sich daraus, wie die equals() Methode nimmt ein Objekt als Parameter an, nicht nur den gleichen Typ wie das Objekt.

Auch wenn es allgemein zutreffend ist, dass viele Klassen equals() so definiert, dass ihre Objekte nur Objekten ihrer eigenen Klasse entsprechen können, gibt es viele Stellen in Java, wo dies nicht der Fall ist. Zum Beispiel ist die Spezifikation für List.equals() besagt, dass zwei Listenobjekte gleich sind, wenn sie beide Listen sind und den gleichen Inhalt haben, auch wenn sie unterschiedliche Implementierungen von List . Um also auf das Beispiel in dieser Frage zurückzukommen, ist es nach der Spezifikation der Methode möglich, eine Map<ArrayList, Something> und dass ich anrufen soll get() mit einer LinkedList als Argument, und es sollte den Schlüssel abrufen, der eine Liste mit demselben Inhalt ist. Dies wäre nicht möglich, wenn get() w

117voto

Jon Skeet Punkte 1325502

Ein großartiger Java-Programmierer bei Google, Kevin Bourrillion, schrieb über genau dieses Problem in einem Blog-Beitrag vor einiger Zeit (zugegebenermaßen im Zusammenhang mit Set anstelle von Map ). Der wichtigste Satz:

Einheitlich sind die Methoden der Java Collections Framework (und auch der Google Collections Library auch) niemals die Typen ihrer Parameter einschränken außer wenn es notwendig ist, um zu verhindern dass die Sammlung nicht zerstört wird.

Ich bin mir nicht ganz sicher, ob ich mit diesem Prinzip einverstanden bin - .NET scheint zum Beispiel den richtigen Schlüsseltyp zu verlangen -, aber es lohnt sich, der Argumentation in diesem Blogbeitrag zu folgen. (Da ich .NET erwähnt habe, sollte man auch erklären, dass ein Teil des Grundes, warum es in .NET kein Problem ist, darin besteht, dass es die größer Problem in .NET mit begrenzterer Varianz...)

31voto

Brian Agnew Punkte 260470

Der Vertrag ist wie folgt formuliert:

Formaler ausgedrückt: Wenn diese Karte eine Abbildung von einem Schlüssel k auf einen Wert v, so dass dass (Schlüssel==Null ? k==Null : key.equals(k) ), dann ist diese Methode v zurück; andernfalls gibt sie null zurück. (Es kann höchstens eine solche Abbildung geben.)

(meine Hervorhebung)

und als solches hängt eine erfolgreiche Schlüsselsuche von der Implementierung der Gleichheitsmethode des Eingabeschlüssels ab. Das ist nicht unbedingt abhängig von der Klasse von k.

15voto

erickson Punkte 256579

Es ist eine Anwendung von Das Postelsche Gesetz, "Sei konservativ in dem, was du tust, sei liberal in dem, was du von anderen akzeptierst."

Gleichheitsprüfungen können unabhängig vom Typ durchgeführt werden; die equals Methode ist definiert auf der Object Klasse und akzeptiert jede Object als Parameter. Es ist also sinnvoll, dass die Schlüsseläquivalenz und Operationen, die auf der Schlüsseläquivalenz basieren, jede Object Typ.

Wenn eine Map Schlüsselwerte zurückgibt, werden so viele Typinformationen wie möglich aufbewahrt, indem der Parameter type verwendet wird.

9voto

Erwin Smout Punkte 17535

Kompatibilität.

Bevor es Generika gab, gab es nur get(Object o).

Hätten sie diese Methode in get(<K> o) geändert, wären die Java-Benutzer möglicherweise gezwungen gewesen, umfangreiche Code-Wartungsarbeiten vorzunehmen, nur um funktionierenden Code wieder kompilieren zu können.

Sie könnte haben eine zusätzlich Methode, sagen wir get_checked(<K> o) und die alte get()-Methode abschaffen, damit es einen sanfteren Übergang gibt. Aber aus irgendeinem Grund wurde dies nicht getan. (Die Situation, in der wir uns jetzt befinden, ist die, dass man Tools wie findBugs installieren muss, um die Typkompatibilität zwischen dem get()-Argument und dem deklarierten Schlüsseltyp <K> der Map zu überprüfen.)

Die Argumente, die sich auf die Semantik von .equals() beziehen, sind meines Erachtens nicht stichhaltig. (Technisch gesehen sind sie korrekt, aber ich halte sie trotzdem für falsch. Kein Designer, der bei Verstand ist, wird jemals o1.equals(o2) wahr machen, wenn o1 und o2 keine gemeinsame Oberklasse haben).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X