22 Stimmen

Bit-Verschiebung in der effektiven Java hashCode() Implementierung

Ich frage mich, ob jemand im Detail erklären könnte, was

(int)(l ^ (l >>> 32));

in der folgenden Hashcode-Implementierung (generiert von eclipse, aber genauso wie Effective Java):

private int i;
private char c; 
private boolean b;
private short s;
private long l;
private double d;
private float f;

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + i;
    result = prime * result + s;
    result = prime * result + (b ? 1231 : 1237);
    result = prime * result + c;
    long t = Double.doubleToLongBits(d);
    result = prime * result + (int) (t ^ (t >>> 32));
    result = prime * result + Float.floatToIntBits(f);
    result = prime * result + (int) (l ^ (l >>> 32));
    return result;
}

Danke!

33voto

Jon Skeet Punkte 1325502

Im Grunde genommen werden die oberen 32 Bits eines Longs mit den unteren 32 Bits XOR-verknüpft. Hier ist eine explodierte Version:

// Unsigned shift by 32 bits, so top 32 bits of topBits will be 0,
// bottom 32 bits of topBits will be the top 32 bits of l
long topBits = l >>> 32;

// XOR topBits with l; the top 32 bits will effectively be left
// alone, but that doesn't matter because of the next step. The
// bottom 32 bits will be the XOR of the top and bottom 32 bits of l
long xor = l ^ topBits;

// Convert the long to an int - this basically ditches the top 32 bits
int hash = (int) xor;

Um auf Ihren Kommentar zu antworten: Sie haben einen Long-Wert, der in einen Int umgewandelt werden muss, um Teil des Hash zu sein (das Ergebnis darf nur 32 Bit haben). Wie wollen Sie das machen? Sie könnte nur die unteren 32 Bits nehmen - aber das bedeutet Änderungen in seulement die obersten 32 Bits würden ignoriert, was keinen sehr guten Hash ergeben würde. Auf diese Weise kann eine Änderung in einem einzigen Bit der Eingabe immer führt zu einer Änderung eines einzigen Bits des Hashwerts. Zugegebenermaßen kann es trotzdem leicht zu Kollisionen kommen - ändern beide Bits 7 und 39, zum Beispiel, oder jedes andere Paar von Bits, die 32 Positionen voneinander entfernt sind - aber das ist zwangsläufig der Fall, da man von 2 64 mögliche Werte auf 2 32 .

0 Stimmen

Was ist der Grund für dieses Vorgehen? Würden Sie nicht einen ebenso gültigen Hashcode erhalten, wenn Sie es nicht täten?

0 Stimmen

@Scobal: Ich habe meine Antwort erweitert, um mehr zu erklären.

0 Stimmen

Und gibt es eine Bedeutung der Konstante 31(int prime) hier oder können wir jede beliebige Primzahl nehmen?

9voto

corsiKa Punkte 79125

Sie nimmt eine 64-Bit-Zahl, teilt sie in zwei Hälften und fügt die beiden Hälften zusammen (im Wesentlichen).

4voto

Alex Martelli Punkte 805329

Er benötigt eine (64-Bit) long l die obere und die untere Hälfte (mit jeweils 32 Bits) zu den unteren 32 Bits eines 64-Bit-Ergebnisses, und nimmt dann nur die unteren 32 Bits mit der (int) Besetzung.

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