Crea hash da stringa e int
-
06-07-2019 - |
Domanda
Ricordo che eclipse e l'idea hanno questo modello per creare automaticamente l'hashCode di un oggetto in base ai suoi attributi.
Una delle strategie se si usano un numero e una stringa è qualcosa del genere.
return stringValue.hashCode() + intValue * 32;
Ooor qualcosa del genere.
Non ho né eclissi né idea a portata di mano e vorrei creare tale funzione.
Modifica
Sulla base delle risposte che creo questa mini-classe
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;
}
}
Questa classe deve essere usata come chiave per una grande mappa di memoria (elementi > 10k) Non voglio iterarli ogni volta per scoprire se String e int sono uguali.
Grazie.
ps .. mmh probabilmente dovrebbe essere un nome StringIntKey.
Soluzione
Usa l'HashcodeBuilder di Apache Commons:
public int hashCode() {
new HashCodeBuilder(17, 37).
append(myString).
append(myInt);
}
Link qui: http://commons.apache.org /lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html
E qui:
http://www.koders.com/java/fidCE4E86F23847AE93909a10439 / p>
Altri suggerimenti
Eclipse svolge sempre più o meno la stessa funzione di hashing, ecco un esempio per una classe con campi in e String as
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;
}
Selezionano sempre 31 come primo, e poi multipli per build nelle funzioni hash o il valore se è una primitiva. Qualcosa del genere non sarebbe difficile da creare come metodo.
public int hashCode(Object ... things) {
final int prime = 31;
int result = 1;
for(Object thing : things) {
result = prime * result + thing.hashCode();
}
return result;
}
Oppure, se non vuoi aggiungere un'altra libreria, fai qualcosa del tipo:
public int hashCode() {
StringBuilder builder = new StringBuilder();
builder.append(myString);
builder.append(myInteger);
return builder.toString().hashCode();
}
Un metodo hashcode è qualcosa che potenzialmente può essere chiamato molte volte e vale quindi la pena di essere ottimizzato. Se il calcolo è complicato, considerare di memorizzare il valore hash. Inoltre, evitare di fare cose che comportano più calcoli del necessario. (Ad esempio, la soluzione StringBuilder impiega la maggior parte del tempo a creare la stringa temporanea.)
L'altra cosa che voglio sottolineare è che la qualità dell'hash è importante. Vuoi evitare qualsiasi algoritmo hashcode che associ molte chiavi comuni. In tal caso, la ricerca della tabella hash potrebbe non essere più O (1). (Nel peggiore dei casi sarà O (N) ... cioè equivalente a una ricerca lineare!). Ecco un esempio di una cattiva funzione hash:
int hashcode() {
int hash = 1;
for (int val : this.values) {
hash = hash * value;
}
return hash;
}
Considera cosa succede se un elemento di this.values ??
è zero ...
Puoi anche usare la classe Objects
dal pacchetto java.util.Objects
per ottenere rapidamente il codice hash.
@Override
public int hashCode() {
return Objects.hash(this.string, this.integerValue, this.otherDataTypes);
}
Oltre alla modifica più recente, se la velocità di recupero è più importante dei problemi di archiviazione, è possibile pre-calcolare e memorizzare il codice hash durante la costruzione della classe StringInt
. Questo è sicuro poiché hai contrassegnato i campi String
e int
come final
, e anche dato che String
è immutabili.
Inoltre, è possibile ottimizzare il metodo equals
controllando che l'oggetto che viene confrontato == questo
prima di effettuare un confronto completo. Vorrei anche raccomandare di fare il confronto basato su int più economico prima di confrontare i campi di stringa.
Un altro suggerimento finale: è possibile modificare il metodo valueOf (String, int)
per costruire un StringInt
o restituire un'istanza precedentemente creata se ne esiste già una con lo stesso String
e valori int. Questo rende la costruzione più costosa ma i confronti sono molto economici in quanto puoi confrontare StringInt
usando " == " sapendo che non saranno mai creati due StringInt
con lo stesso valore String
e int
.