23

hashCode メソッドを使用して Java 文字列の等価性をテストできない理由はありますか? 基本的に、代わりに....

"hello".equals("hello")

あなたが使用することができます...

"hello".hashCode() == "hello".hashCode()

文字列がハッシュコードを計算すると、文字列がハッシュコードをキャッシュするため、文字列を比較するのはintを比較するのと同じくらい効率的であり、文字列が文字列プールにある可能性が高いため、これは便利です仕方。

4

9 に答える 9

39

理由: オブジェクトが等しい場合、2 つのオブジェクトの hashCodes は等しくなければなりませんが、2 つのオブジェクトが等しくない場合でも、hashCode は等しい可能性があります。

(コメント後に変更)

于 2009-09-23T12:17:57.390 に答える
39

反例をあげましょう。これを試して、

public static void main(String[] args) {
    String str1 = "0-42L";
    String str2 = "0-43-";

    System.out.println("String equality: " + str1.equals(str2));
    System.out.println("HashCode eqauality: " + (str1.hashCode() == str2.hashCode()));
}

私のJavaでの結果、

String equality: false
HashCode eqauality: true
于 2009-09-23T12:38:24.960 に答える
16

多くの人が、hashCode は一意性を保証しないと言っていました。実際、非常に単純な理由でそれを行うことはできません。

hashCode は int を返します。これは、2^32 の可能な値 (約 4,000,000,000) があることを意味しますが、2^32 を超える可能性のある文字列が確実にあり、少なくとも 2 つの文字列が同じハッシュコード値を持つことを意味します。

これはピジョンホールの原理と呼ばれます。

于 2009-09-23T12:50:13.927 に答える
8

うまくいかない理由を指摘する人もいます。したがって、とにかくゲインが最小限になるという補遺を追加します。

Java で 2 つの文字列を比較する場合、String equals 関数は、最初にそれらが同じオブジェクトへの 2 つの参照であるかどうかをチェックします。その場合は、すぐに true を返します。次に、長さが等しいかどうかをチェックします。そうでない場合は false を返します。そうして初めて、文字ごとの比較が開始されます。

メモリ内のデータを操作している場合、同じオブジェクトの比較は「同じ」ケースをすばやく処理できます。これは、4バイトの整数の比較であると思います。(オブジェクトハンドルの長さが間違っていたら誰か訂正してください。)

等しくない文字列のほとんどは、長さを比較するとすぐに等しくないことがわかるはずです。2 つの名前 (顧客、都市、製品など) を比較する場合、通常、それらの長さは等しくありません。そのため、単純な int 比較でそれらをすばやく破棄できます。

パフォーマンスの最悪のケースは、2 つの長い同一のオブジェクト文字列になることです。次に、オブジェクト ハンドルの比較、偽、チェックの継続を実行する必要があります。長さの比較、真、チェックを続けます。次に、文字列の全長を 1 文字ずつ調べて、最後まで同じであることを確認します。

于 2009-09-23T13:10:08.800 に答える
4

使用して必要な効果を得ることができますString.intern()(ハッシュ テーブルを使用して実装されます)。

演算子をintern()使用して戻り値を比較できます。==それらが同じ文字列を参照している場合、元の文字列は同等であり (つまり、equals()が返されるtrue)、ポインタ比較のみが必要です (比較と同じコストがかかりintます)。

String a = "Hello";
String b = "Hel" + "lo";

System.out.println(a.equals(b));
System.out.println(a == b);

String a2 = a.intern();
String b2 = b.intern();

System.out.println(a2.equals(b2));
System.out.println(a2 == b2);

出力:

true
false
true
true
于 2009-09-23T12:46:58.753 に答える
1

hashCode 値は一意ではありません。つまり、文字列が実際には一致しない可能性があります。パフォーマンスを向上させるために、多くの場合、equals の実装では、面倒なチェックを実行する前に hashCode チェックを実行します。

于 2009-09-23T12:18:29.543 に答える
1

非常に単純な理由: 衝突のリスク... ハッシュ コードは、文字列よりも可能な値がはるかに少なくなります。生成するハッシュの種類によって少し異なりますが、非常に単純な例を見てみましょう。ここでは、文字の序数値を追加し、その位置で乗算します: a=1、b=2 など。したがって、「hello」は変換: h: 8x1=8、e: 5x2=10、l: 12x3=36、l: 12x4=48、o: 15x5=75。8+10+36+48+75=177.

177 ハッシュとして終了する可能性のある他の文字列値はありますか? もちろん!たくさんのオプション。いろいろ計算してみてください。

それでも、このハッシュ化方法は単純な方法を使用していました。Java と .NET は、このような衝突の可能性がはるかに低い、より複雑なハッシュ アルゴリズムを使用します。それでも、2 つの異なる文字列が同じハッシュ値になる可能性があるため、この方法は信頼性が低くなります。

于 2009-09-23T12:23:09.797 に答える
-2

あなたが説明したように hashCode を使用しない理由はありません。

ただし、衝突に注意する必要があります。2 つの異なる文字列が同じ値にハッシュされる可能性があります (確かに小さな可能性です)。最初に hashCode を実行することを検討し、等しい場合は equals() を使用して完全な比較も実行します。

于 2009-09-23T12:19:26.750 に答える