2009-07-30 7 views
11

Ich erinnere mich an Eclipse und Idee haben diese Vorlage, um automatisch einen HashCode eines Objekts basierend auf seinen Attributen erstellen.Create Hash von String und int

Eine der Strategien, wenn eine Zahl und ein String verwendet wird, ist etwa so.

return stringValue.hashCode() + intValue * 32; 

Ooor etwas wie das.

Ich habe noch keine Eclipse oder Idee zur Hand und ich möchte eine solche Funktion erstellen.

EDIT

Basierend auf den Antworten, die ich diese Mini-Klasse ist

class StringInt { 
     private final String s; 
     private final int i; 

     static StringInt valueOf(String string , int value) { 
      return new StringInt(string, value); 
     } 
     private StringInt(String string, int value) { 
      this.s = string; 
      this.i = value; 
     } 
     public boolean equals(Object o) { 
      if(o != null && o instanceof StringInt){ 
       StringInt other = (StringInt) o; 
       return this.s == other.s && this.i == other.i; 
      } 

      return false; 
     } 
     public int hashCode() { 
      return s != null ? s.hashCode() * 37 + i : i; 
     } 
    } 

Diese Klasse erstellen als Schlüssel für eine große Speicherkarte verwendet werden (> 10k Elemente) Ich glaube nicht, Ich möchte sie jedes Mal wiederholen, um herauszufinden, ob String und int identisch sind.

Vielen Dank.

PS .. mmh wahrscheinlich sollte es Namen StringIntKey sein.

+0

Oscar, ich denke, das ist eine gute Klasse. Die Methode hashCode ist klar, zuverlässig und performant. Wie verhindert man, dass die Zeichenfolge null ist? Werfen Sie in Ihrem Konstruktor eine NPE, wenn es NULL ist. Dann könnten Sie diese Null-Wächter in equals und hashCode entfernen. Schließlich halten Sie eine Kopie von "Effektives Java" praktisch für Fragen wie diese. Die von Eclipse und IDEA erstellten hashCode-Methoden basieren auf diesem Buch. –

+0

In Ihrer equals-Methode sollte die Zeichenkette use = anstelle von == verglichen werden. –

Antwort

8

Verwenden Sie den Apache Commons HashcodeBuilder:

public int hashCode() { 
    new HashCodeBuilder(17, 37). 
      append(myString). 
      append(myInt); 
} 

Link-hier: http://commons.apache.org/lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html

Und hier:

http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx

+0

Ist der HashCodeBuilder-Quellcode online? Ich sehe es mir an. – OscarRyz

+0

heißt es: string.hashCode * 37 + intValue !! genug für mich !! Danke – OscarRyz

3

Oder, wenn Sie eine andere Bibliothek nicht hinzufügen möchten, , tun Sie etwas wie das Folgende:

public int hashCode() { 
    StringBuilder builder = new StringBuilder(); 
    builder.append(myString); 
    builder.append(myInteger); 
    return builder.toString().hashCode(); 
} 
+0

Doh! .. manchmal vermisse ich diese Art von Lösungen !! Ja, ich möchte keine weitere Bibliothek hinzufügen. Danke für den Hinweis – OscarRyz

+2

@aperkins: es ist einfacher, einfach "return (myString + myInteger) .hashCode()" zu schreiben. Der Java-Compiler kompiliert dies in die entsprechende Sequenz von StringBuilder.append-Aufrufen. –

+2

@perkins: eine andere Sache, wenn Sie wirklich über die Geschwindigkeit besorgt sind, dann ist dieser Ansatz wesentlich langsamer als das Berechnen und Kombinieren von Komponenten-Hashcodes. –

3

Eclipse-immer hat in etwa die gleiche Hash-Funktion, hier ist ein Beispiel für eine Klasse mit einem in und String als Felder

public int hashCode() { 
     final int prime = 31; 
     int result = 1; 
     result = prime * result + this.interger; 
     result = prime * result + ((this.string == null) ? 0 : this.string.hashCode()); 
     return result; 
    } 

Sie immer 31 als Haupt holen, und dann mehrfach von Build in Hash-Funktionen oder der Wert, wenn es ein Grundelement ist. So etwas wäre nicht schwer als Methode zu erstellen.

 public int hashCode(Object ... things) { 
     final int prime = 31; 
     int result = 1; 
     for(Object thing : things) { 
      result = prime * result + thing.hashCode(); 
     } 
     return result; 
    } 
0

Zusätzlich zu Ihrem letzten bearbeiten, wenn Abrufgeschwindigkeit wichtiger als Speicher Anliegen ist, könnte man-Compute vor und den Hash-Code speichern, wenn Ihre StringInt Klasse zu bauen. Dies ist sicher, da Sie die Felder String und int als final markiert haben, und auch vorausgesetzt, dass String unveränderlich ist.

Sie können auch Ihre equals Methode optimieren, indem Sie vor einem vollständigen Vergleich prüfen, ob das zu vergleichende Objekt == this ist. Ich würde auch empfehlen, zuerst den billigeren int-basierten Vergleich zu machen, bevor man die String-Felder vergleicht.

Ein weiterer letzter Vorschlag: Sie könnten Ihre valueOf(String, int) Methode ändern entweder eine StringInt oder Rückkehr konstruieren eine zuvor erstellte Instanz, wenn man bereits mit den gleichen String und int-Werte vorhanden ist.Dies macht die Konstruktion teurer, aber Vergleiche sehr billig, wie Sie s mit "==" in dem Wissen vergleichen können, dass nie zwei StringInt s mit dem gleichen Wert String und int Wert erstellt werden.

1

Eine Hashcode-Methode wird möglicherweise mehrmals aufgerufen und ist daher eine Optimierung wert. Wenn die Berechnung kompliziert ist, erwägen Sie, den Hash-Wert zu memotieren. Vermeiden Sie auch Dinge, die mehr Berechnungen als nötig erfordern. (Die StringBuilder-Lösung verbringt die meiste Zeit damit, die temporäre Zeichenfolge zu erstellen.)

Die andere Sache, auf die ich hinweisen möchte, ist, dass die Qualität des Hash wichtig ist. Sie möchten jeden Hashcode-Algorithmus vermeiden, der viele gängige Schlüssel abbildet. Wenn dies geschieht, ist die Hashtabellensuche möglicherweise nicht mehr O (1). (Im schlimmsten Fall ist es O (N) ... d. H. Äquivalent zu einer linearen Suche!). Hier ist ein Beispiel für eine schlechte Hash-Funktion:

int hashcode() { 
    int hash = 1; 
    for (int val : this.values) { 
     hash = hash * value; 
    } 
    return hash; 
} 

überlegen Sie, was passiert, wenn ein Element der this.values Null ist ...

0

Sie können auch Objects Klasse von java.util.Objects Paket verwenden, um schnell Hash-Code zu erhalten.

@Override 
public int hashCode() { 
    return Objects.hash(this.string, this.integerValue, this.otherDataTypes); 
}