Es gibt Fälle, in denen die in map verwendeten Schlüsselobjekte hashCode () und equals () nicht von Object überschreiben. Verwenden Sie zum Beispiel eine Socket-Verbindung oder java.lang.Class als Schlüssel.
Wenn equals()
und hashCode()
für Schlüsselobjekte nicht überschrieben werden, sollten HashMap und IdentityHashMap die gleiche Semantik haben. Die standardmäßige equals () - Implementierung verwendet Referenzsemantik, und der Standardwert hashCode()
ist der Systemidentitätshashcode des Objekts.
Dies ist nur in Fällen schädlich, in denen verschiedene Instanzen eines Objekts als logisch gleich betrachtet werden können. Zum Beispiel würden Sie IdentityHashMap nicht verwenden wollen, wenn Ihre Schlüssel:
wären %Vor%und
%Vor% Da dies technisch unterschiedliche Instanzen der Integer-Klasse sind. (Sie sollten wirklich Integer.valueOf(1)
verwenden, aber das wird off-topic.)
Class
als Schlüssel sollte in Ordnung sein, außer in ganz besonderen Fällen (zum Beispiel generiert die Hibernate ORM-Bibliothek Unterklassen Ihrer Klassen zur Laufzeit, um einen Proxy zu implementieren.) Als Entwickler wäre ich skeptisch gegenüber Code, der speichert Connection
Objekte in einer Map als Schlüssel (vielleicht sollten Sie einen Verbindungspool verwenden, wenn Sie Datenbankverbindungen verwalten?). Ob sie funktionieren oder nicht, hängt von der Implementierung ab (da Connection nur eine Schnittstelle ist).
Beachten Sie auch, dass HashMap erwartet, dass die Bestimmung von equals()
und hashCode()
konstant bleibt. Insbesondere wenn Sie eine benutzerdefinierte hashCode()
implementieren, die veränderbare Felder für das Schlüsselobjekt verwendet, kann das Ändern eines Schlüsselfelds dazu führen, dass der Schlüssel im falschen Hashtabellenbereich der HashMap verloren geht. In diesen Fällen können Sie möglicherweise IdentityHashMap verwenden (abhängig vom Objekt und Ihrem speziellen Anwendungsfall), oder Sie benötigen möglicherweise nur eine andere equals()/hashCode()
-Implementierung.
Aus Sicht der mobilen Codesicherheit gibt es Situationen, in denen die Verwendung von IdentityHashMap
oder ähnlich notwendig wird. Schädliche Implementierungen von Nicht- final
-Schlüsselklassen können hashCode
und equals
als schädlich überschreiben. Sie können zum Beispiel Anspruch auf Gleichheit mit verschiedenen Instanzen erheben, einen Verweis auf andere Instanzen erhalten, mit denen sie verglichen werden usw. Ich schlage vor, mit der Standardpraxis zu brechen, indem man sicher bleibt und IdentityHashMap
verwendet, wo man Identitätssemantik haben möchte. Es gibt selten einen guten Grund, die Bedeutung von Gleichheit in einer Unterklasse zu ändern, in der die Oberklasse bereits verglichen wird. Ich denke, das wahrscheinlichste Szenario ist ein gebrochener, nicht symmetrischer Proxy.
Die Implementierung von IdentityHashMap
unterscheidet sich ziemlich von HashMap
. Sie verwendet lineare Suchobjekte und nicht Entry
-Objekte als Verknüpfungen in einer Kette. Dies führt zu einer geringfügigen Verringerung der Anzahl von Objekten, obwohl ein ziemlich kleiner Unterschied im Gesamtspeicher verwendet wird. Ich habe keine guten Leistungsstatistiken, die ich nennen kann. Es gab einen Leistungsunterschied zwischen der Verwendung von (nicht überschriebenen) Object.hashCode
und System.identityHashCode
, aber das wurde vor ein paar Jahren geklärt.
In der von Ihnen beschriebenen Situation ist das Verhalten von HashMap und IdentityHashMap identisch.
Im Gegensatz dazu unterscheiden sich die Verhaltensweisen zweier Maps, wenn die Schlüssel die Werte equals () und hashCode () überschreiben.
Siehe javadoc von java.util.IdentityHashMap.
Diese Klasse implementiert die Map-Schnittstelle mit einer Hashtabelle, wobei beim Vergleichen von Schlüsseln (und Werten) die Gleichheit der Objekte anstelle der Objektgleichheit verwendet wird. Mit anderen Worten, in einer IdentityHashMap werden zwei Schlüssel k1 und k2 genau dann als gleich betrachtet, wenn (k1 == k2). (In normalen Map-Implementierungen (wie HashMap) werden zwei Schlüssel k1 und k2 genau dann als gleich betrachtet, wenn (k1 == null? K2 == null: k1.equals (k2)).)
Zusammenfassend lautet meine Antwort:
Obwohl es kein theoretisches Problem gibt, sollten Sie IdentityHashMap
vermeiden, es sei denn, Sie haben einen expliziten Grund, es zu benutzen. Es bietet keine nennenswerte Leistung oder einen anderen Vorteil im allgemeinen Fall, und wenn Sie unweigerlich damit beginnen, Objekte in die Karte einzubringen, die tun equals()
und hashCode()
überschreiben, werden Sie mit subtilen, harten Ergebnissen enden Diagnose-Bugs.
Wenn Sie glauben, dass Sie aus Leistungsgründen IdentityHashMap
benötigen, verwenden Sie einen Profiler, um diesen Verdacht zu bestätigen, bevor Sie den Wechsel vornehmen. Ich schätze, Sie werden viele andere Möglichkeiten zur Optimierung finden, die sowohl sicherer sind als auch einen größeren Unterschied machen.
Soweit ich weiß, wäre das einzige Problem mit einer Hashmappe mit schlechten Schlüsseln, mit sehr großen Hashmaps - Ihre Schlüssel könnten sehr schlecht sein und Sie erhalten o (n) Retrievalzeit statt o (1). Wenn es etwas anderes kaputt macht, wäre ich daran interessiert, es trotzdem zu hören:)
Tags und Links java