Konsistenz von hashCode () in einer Java-Zeichenfolge



Answers

Ich habe etwas über JDK 1.0 und 1.1 und> = 1.2 gefunden:

In JDK 1.0.x und 1.1.x arbeitete die Funktion hashCode für lange Strings, indem sie jedes n-te Zeichen abtastete. Dies garantiert, dass Sie viele Strings auf denselben Wert hashen und Hashtable Lookup verlangsamen. In JDK 1.2 wurde die Funktion verbessert, das Ergebnis um 31 zu multiplizieren und dann das nächste Zeichen der Reihe nach hinzuzufügen. Dies ist ein wenig langsamer, aber Kollisionen können besser vermieden werden. Quelle: http://mindprod.com/jgloss/hashcode.html

Etwas anderes, weil Sie eine Nummer zu brauchen scheinen: Wie wäre es mit CRC32 oder MD5 anstelle von Hashcode und Sie sind gut zu gehen - keine Diskussionen und keine Sorgen ...

Question

Der hashCode-Wert einer Java- String.hashCode() wird als ( String.hashCode() ) berechnet:

s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

Gibt es Umstände (z. B. JVM-Version, Lieferant usw.), unter denen der folgende Ausdruck als falsch bewertet wird?

boolean expression = "This is a Java string".hashCode() == 586653468

Update # 1: Wenn Sie behaupten, dass die Antwort "Ja, es gibt solche Umstände" - dann geben Sie ein konkretes Beispiel, wenn "Dies ist ein Java-String" .hashCode ()! = 586653468. Versuchen Sie, so spezifisch / konkret wie möglich.

Update # 2: Wir wissen alle, dass es generell schlecht ist, sich auf die Implementierungsdetails von hashCode () zu verlassen. Ich spreche jedoch speziell über String.hashCode () - also bitte behalte die Antwort auf String.hashCode (). Object.hashCode () ist im Zusammenhang mit dieser Frage völlig irrelevant.




Nur um Ihre Frage zu beantworten und keine Diskussionen fortzusetzen. Die Apache Harmony JDK-Implementierung scheint einen anderen Algorithmus zu verwenden, zumindest sieht sie völlig anders aus:

Sonne JDK

public int hashCode() {
    int h = hash;
    if (h == 0) {
        int off = offset;
        char val[] = value;
        int len = count;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}

Apache Harmonie

public int hashCode() {
    if (hashCode == 0) {
        int hash = 0, multiplier = 1;
        for (int i = offset + count - 1; i >= offset; i--) {
            hash += value[i] * multiplier;
            int shifted = multiplier << 5;
            multiplier = shifted - multiplier;
        }
        hashCode = hash;
    }
    return hashCode;
}

Fühlen Sie sich frei, es selbst zu überprüfen ...




Wie oben gesagt, sollten Sie sich im Allgemeinen nicht darauf verlassen, dass der Hash-Code einer Klasse gleich bleibt. Beachten Sie, dass sogar nachfolgende Läufe derselben Anwendung auf derselben VM andere Hashwerte erzeugen können. AFAIK the Sun JVMs Hash-Funktion berechnet bei jedem Lauf den gleichen Hash, aber das ist nicht garantiert.

Beachten Sie, dass dies nicht theoretisch ist. Die Hash-Funktion für java.lang.String wurde in JDK1.2 geändert (der alte Hash hatte Probleme mit hierarchischen Strings wie URLs oder Dateinamen, da er dazu tendierte, den gleichen Hash für Strings zu erzeugen, die sich nur am Ende unterschieden).

java.lang.String ist ein Sonderfall, da der Algorithmus seiner hashCode () (jetzt) ​​dokumentiert ist, so dass Sie sich darauf verlassen können. Ich würde es immer noch als schlechte Übung ansehen. Wenn Sie einen Hash-Algorithmus mit speziellen, dokumentierten Eigenschaften benötigen, schreiben Sie einfach einen :-).




Links