Frage

Diese Frage wird von seltsam HashMap.put () Verhalten

Ich glaube, ich verstehe, warum Map<K,V>.put eine K nimmt aber Map<K,V>.get nimmt einen Object, scheint es nicht so zu tun brechen zu viel vorhandenen Code.

Jetzt kommen wir in ein sehr fehleranfällig Szenario:

java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(5L,"Five"); // compiler barfs on m.put(5, "Five")
m.contains(5); // no complains from compiler, but returns false

Könnte dies nicht durch Rückgabe true, wenn der Wert Long gelöst worden war int Bereich withing und die Werte gleich sind?

War es hilfreich?

Lösung

Hier ist die Quelle von Long.java

public boolean equals(Object obj) {
    if (obj instanceof Long) {
        return value == ((Long)obj).longValue();
    }
    return false;
}

d. es braucht ein langer Typen gleich zu sein. Ich glaube, der entscheidende Unterschied zwischen:

long l = 42L
int i = 42;
l == i

und Ihr Beispiel oben ist, dass mit Primitiven kann eine implizite Erweiterung des int-Wert auftreten, jedoch mit Objekttypen gibt es keine Regeln für von Integer auf eine lange implizit umgewandelt wird.

Überprüfen Sie auch Java Puzzlers es viele Beispiele ähnlich wie diese hat.

Andere Tipps

Ihre Frage scheint auf den ersten Blick sinnvoll, aber es wäre ein Verstoß gegen die allgemeinen Konventionen für equals (), wenn nicht seinen Vertrag, sein true zurück für zwei verschiedene Typen.

Ein Teil der Design-Sprache Java war für Objekte niemals implizit auf andere Typen zu konvertieren, im Gegensatz zu C ++. Dies war Teil macht Java eine kleine, einfache Sprache. Ein angemessener Teil der C ++ 's Komplexität kommt von impliziten Konvertierungen und ihre Wechselwirkungen mit anderen Funktionen.

Auch hat Java eine scharfe und sichtbare Dichotomie zwischen Primitiven und Objekten. Dies unterscheidet sich von anderen Sprachen, in denen diese Differenz unter die Decke als Optimierungs verborgen ist. Das bedeutet, dass Sie können nicht erwarten, lange und Integer wie lange und int zu handeln.

In der Bibliothek Code geschrieben werden kann, diese Unterschiede zu verbergen, aber das kann, indem die Programmierumgebung weniger konsistent Schaden tatsächlich tun.

So Sie Code sollte sein ....

java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(5L, "Five"); // compiler barfs on m.put(5, "Five")
System.out.println(m.containsKey(5L)); // true

Sie vergessen, dass Java-Code wird Autoboxing, so dass der obige Code würde

equivelenet werden
java.util.HashMap<Long, String> m = new java.util.HashMap<Long, String>();
m.put(new Long(5L), "Five"); // compiler barfs on m.put(5, "Five")
System.out.println(m.containsKey(new Long(5))); // true
System.out.println(m.containsKey(new Long(5L))); // true

So ein Teil des Problems ist die Autoboxing. Der andere Teil ist, dass man verschiedene Typen haben wie andere Plakate angegeben haben.

Die anderen Antworten hinreichend erklären, warum es nicht, aber keiner von ihnen angesprochen werden, wie Code zu schreiben, weniger Fehler, um dieses Problem anfällig sind. Mit erinnert Typ-Casts (keine Compiler-Hilfe), Suffix Primitiven mit L usw. ist einfach nicht akzeptabel IMHO.

hinzufügen

Ich empfehle, die GNU Grube Bibliothek von Sammlungen zu verwenden, wenn Sie Primitiven haben (und in vielen anderen Fällen). Zum Beispiel gibt es eine TLongLongHashMap, die Dinge interally als primitive longs speichert. Als Ergebnis beenden Sie nie mit Boxen / Unboxing-up, und nie mit unerwartetem Verhalten am Ende:

TLongLongHashMap map = new TLongLongHashMap();
map.put(1L, 45L);
map.containsKey(1); // returns true, 1 gets promoted to long from int by compiler
int x = map.get(1); // Helpful compiler error. x is not a long
int x = (int)map.get(1); // OK. cast reassures compiler that you know
long x = map.get(1); // Better.

und so weiter. Es besteht keine Notwendigkeit, die Art Recht zu bekommen, und der Compiler gibt einen Fehler (die Sie korrigieren oder überschreiben können), wenn Sie etwas tun, dumm (versuchen, eine lange in einem int zu speichern).

Die Regeln des Auto-Casting bedeuten, dass Vergleiche richtig so gut funktionieren:

if(map.get(1) == 45) // 1 promoted to long, 45 promoted to long...all is well

Als Bonus die Speicher-Overhead und die Laufzeitleistung ist viel besser.

scroll top