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

6voto

Apocalisp Punkte 34088

Der Grund dafür ist, dass die Eindämmung bestimmt wird durch equals y hashCode die Methoden sind auf Object und beide nehmen eine Object Parameter. Dies war ein früher Konstruktionsfehler in den Standardbibliotheken von Java. Gepaart mit Einschränkungen im Java-Typsystem zwingt es alles, was auf equals und hashCode beruht, dazu, die Object .

Die einzige Möglichkeit, typsichere Hash-Tabellen und Gleichheit in Java zu haben, ist der Verzicht auf Object.equals y Object.hashCode und verwenden Sie einen generischen Ersatz. Funktions-Java verfügt über Typklassen für genau diesen Zweck: Hash<A> y Equal<A> . Ein Wrapper für HashMap<K, V> ist vorgesehen, dass Hash<K> y Equal<K> in seinem Konstruktor. Der Konstruktor dieser Klasse get y contains Methoden nehmen daher ein generisches Argument vom Typ K .

Exemple :

HashMap<String, Integer> h =
  new HashMap<String, Integer>(Equal.stringEqual, Hash.stringHash);

h.add("one", 1);

h.get("one"); // All good

h.get(Integer.valueOf(1)); // Compiler error

5voto

Owheee Punkte 51

Es gibt noch einen weiteren gewichtigen Grund: Es ist technisch nicht machbar, weil es die Karte sprengt.

Java hat polymorphe generische Konstruktionen wie <? extends SomeClass> . Ein so markierter Verweis kann auf einen Typ verweisen, der mit <AnySubclassOfSomeClass> . Aber polymorphe generische macht diese Referenz readonly . Der Compiler erlaubt die Verwendung von generischen Typen nur als Rückgabetyp von Methoden (wie einfache Getter), blockiert aber die Verwendung von Methoden, bei denen der generische Typ das Argument ist (wie gewöhnliche Setter). Das bedeutet, wenn Sie schreiben Map<? extends KeyType, ValueType> erlaubt es der Compiler nicht, die Methode get(<? extends KeyType>) und die Karte wird unbrauchbar sein. Die einzige Lösung ist, diese Methode nicht generisch zu machen: get(Object) .

2voto

henva Punkte 21

Wir machen gerade ein großes Refactoring und uns fehlte dieses stark typisierte get(), um zu überprüfen, ob wir nicht ein get() mit altem Typ verpasst haben.

Aber ich fand Umgehung / hässlichen Trick für Kompilierungszeit überprüfen: erstellen Sie Map-Schnittstelle mit stark typisierte get, containsKey, entfernen... und legte es in java.util-Paket Ihres Projekts.

Sie erhalten Kompilierungsfehler nur für den Aufruf von get(), ... mit falschen Typen, alles andere scheint ok für Compiler (zumindest in Eclipse Kepler).

Vergessen Sie nicht, diese Schnittstelle nach der Überprüfung Ihres Builds zu löschen, da dies nicht das ist, was Sie zur Laufzeit wollen.

1voto

Anton Gogolev Punkte 109749

Abwärtskompatibilität, denke ich. Map (oder HashMap ) muss noch unterstützen get(Object) .

1voto

Stilgar Punkte 21139

Ich habe mir das angeschaut und überlegt, warum sie das so gemacht haben. Ich glaube nicht, dass eine der vorhandenen Antworten erklärt, warum sie nicht einfach die neue generische Schnittstelle so gestalten konnten, dass sie nur den richtigen Typ für den Schlüssel akzeptiert. Der eigentliche Grund ist, dass sie trotz der Einführung von Generika KEINE neue Schnittstelle geschaffen haben. Die Map-Schnittstelle ist die gleiche alte nicht-generische Map, sie dient nur als generische und nicht-generische Version. Wenn Sie also eine Methode haben, die eine nicht-generische Map akzeptiert, können Sie ihr eine Map<String, Customer> und es würde trotzdem funktionieren. Gleichzeitig akzeptiert der Vertrag für get Object, so dass die neue Schnittstelle auch diesen Vertrag unterstützen sollte.

Meiner Meinung nach hätten sie eine neue Schnittstelle hinzufügen und beides in die bestehende Sammlung implementieren sollen, aber sie haben sich für kompatible Schnittstellen entschieden, auch wenn das schlechteres Design für die get-Methode bedeutet. Beachten Sie, dass die Sammlungen selbst mit den bestehenden Methoden kompatibel wären, nur die Schnittstellen nicht.

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