Java文字列のhashCode値は、次のように計算されます。String.hashCode()):
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
次の式がfalseと評価されるような状況(JVMのバージョン、ベンダーなど)はありますか?
boolean expression = "This is a Java string".hashCode() == 586653468
更新1:答えが「はい、そのような状況がある」と主張するのであれば、「これはJava文字列です。」.hashCode()!= 586653468の場合の具体例を教えてください。
更新2:hashCode()の実装の詳細に頼るのは一般的に悪いことを私たち全員が知っています。しかし、私は特にString.hashCode()について話しています - そのため、答えはString.hashCode()に集中してください。 Object.hashCode()は、この質問とは無関係です。
その文書はJava 1.2までさかのぼります。
それは本当ですが一般にハッシュコードの実装が同じであることに頼るべきではありません。java.lang.String
したがって、それを変更すると既存の契約が破られることになります。
可能であれば、バージョン間でハッシュコードが同じであることに頼るべきではありません。java.lang.String
アルゴリズムが単純だからです。持っているアルゴリズムが指定される前にリリースとの互換性を放棄しても構わない限り、...は指定されています。
私はJDK 1.0と1.1と> = 1.2について何かを見つけました:
JDK 1.0.xおよび1.1.xではhashCode 長い文字列のための関数 n文字ごとにサンプリングします。この かなりよく保証されているでしょう 多くの文字列が同じハッシュ 値、したがってHashtableを遅くする 見上げる。 JDK 1.2では、この関数は 結果を乗算するように改善されました これまでのところ31までに次のものを追加 シーケンス内の文字これは 少し遅くなりますが、 衝突を避けます。 ソース:http://mindprod.com/jgloss/hashcode.html
ハッシュコードの代わりにCRC32やMD5を使用しても問題ありません。ディスカッションも心配もまったく必要ありません。
ハッシュコードが特定の値に等しいとは限りません。それが同じ実行内で一貫した結果を返すということだけです。 APIドキュメントは次のように言っています。
hashCodeの一般規約は次のとおりです。
- Javaアプリケーションの実行中に同じオブジェクトに対して複数回呼び出される場合は、オブジェクトの等価比較で使用される情報が変更されていない限り、hashCodeメソッドは常に同じ整数を返す必要があります。この整数は、アプリケーションの実行ごとに同じアプリケーションの実行ごとに一貫性を保つ必要はありません。
編集String.hashCode()のjavadocは、Stringのハッシュコードの計算方法を指定しているので、これに違反すると公開APIの仕様に違反します。
上記のように、一般的にはクラスのハッシュコードが同じであることに頼るべきではありません。それ以降の実行でも、同じアプリケーションに同じVM異なるハッシュ値を生成する可能性があります。 Sun JVMのハッシュ関数は、実行ごとに同じハッシュを計算することに注意してください。ただし、これは保証されていません。
これは理論的なことではありません。 java.lang.Stringのハッシュ関数かわったJDK 1.2では(URLやファイル名のような階層的な文字列で問題がありました。文字列に対して同じハッシュが生成される傾向があったため、末尾が異なるだけでした)。
hashCode()のアルゴリズムは(現在)文書化されているので、java.lang.Stringは特別な場合です。したがって、おそらくそれに頼ることができます。私はまだそれを悪い習慣だと思います。特別な、文書化された特性を持つハッシュアルゴリズムが必要な場合は、ただ1つ書いてください:-)
心配しなければならないもう1つの(!)問題は、Javaの初期/後期バージョン間で実装が変更される可能性があることです。実装の詳細がすぐに決まっているとは思わないので、潜在的には未来Javaバージョンは問題を引き起こす可能性があります。
肝心なのは、私はの実装に依存しないでしょうhashCode()
。
たぶん、あなたはこのメカニズムを使って実際にどんな問題を解決しようとしているのかを強調することができ、そしてそれはより適切なアプローチを強調するでしょう。
switch
文字列に対するステートメントは、特定の固定ハッシュコードに依存するコードにコンパイルされます。String
のハッシュコードアルゴリズムは間違いなく既存のコードを破壊するでしょう… - Holger
あなたの質問に答えるためだけに話し合いを続けないために。 Apache Harmony JDK実装は異なるアルゴリズムを使用しているようですが、少なくともまったく違って見えます。
Sun 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;
}
アパッチハーモニー
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;
}
自分でチェックしてみてください。
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
間違えない限り、これはAndroidがSunのStringオブジェクトの実装を変更せずに使用しているためです。 - K_7
変更やおそらく互換性のないVMが心配な場合は、既存のハッシュコード実装を独自のユーティリティクラスにコピーして、それを使ってハッシュコードを生成してください。