6
public static void main(String[] args) {
    HashSet set = new HashSet(); 
    set.add(new StringBuffer("abc"));
    set.add(new StringBuffer("abc")); 
    set.add(new StringBuffer("abc"));
    set.add(new StringBuffer("abc")); 
    System.out.println(set); 
}

出力:

[abc,abc,abc,abc]

上記のコードでは、オブジェクトをStringBuffer("abc")何度もSet追加して追加しましたが、セットは重複を追加しません。

4

6 に答える 6

13

StringBufferObject#equals()はandをオーバーライドしないObject#hashCode()StringBufferため、インスタンスの識別はバッファの内容ではなく、メモリ内のオブジェクトのアドレスに基づいています。*


* ID がメモリ内のアドレスに基づいていることは、JLS では厳密に要求されているわけではありませんが、一般的なObject#hashCode()実装の結果です。JavaDoc から:

合理的に実用的である限り、クラスで定義された hashCode メソッドはObject、個別のオブジェクトに対して個別の整数を返します。(これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法は Java™ プログラミング言語では必要ありません。)

于 2013-07-04T05:39:49.980 に答える
8

StringBufferequalsまたはどちらもオーバーライドしないhashCodeため、各オブジェクトはそれ自体とのみ等しくなります。

これは非常に「設計上変更可能」であるため、理にかなっていStringBufferます。また、2 つの変更可能なオブジェクトが互いに等しい場合、一方が変更される可能性があるため、同等であると問題が発生する可能性があります。変更可能なオブジェクトをマップまたはセットの一部のキーとして使用すると、問題が発生する可能性があります。コレクションへの挿入後に 1 つを変更すると、ハッシュ コードが変更される可能性があるため、コレクション内のエントリが無効になります。たとえば、マップでは、最初のテストがハッシュ コードによるものであるため、キーと同じオブジェクトで値を検索することさえできません。

StringBuffer(およびStringBuilder) は非常に一時的なオブジェクトになるように設計されています。それらを作成し、追加し、文字列に変換すれば完了です。それらをコレクションに追加することに気付いたときはいつでも、一歩下がって、それが本当に意味があるかどうかを確認する必要があります. たまにそうなるかもしれませんが、通常はコレクション自体が短命の場合に限られます

オーバーライドするときは、独自のコードでこれを考慮する必要がequalsありhashCodeます。また、オブジェクトのミュータブルな側面に基づいて等価性を保つことはほとんどありません。クラスを正しく使用することが難しくなり、デバッグに長い時間がかかる微妙なバグに簡単につながる可能性があります。

于 2013-07-04T05:41:42.200 に答える
1

StringBuffer に equals() メソッド (またはその欠如) があることに気付きましたか? そこに答えがあります。

Set またはハッシュ ベースのコレクションは、その動作特性について、オブジェクトの equals() および hashcode() メソッドによって公開されるコントラクトに依存します。

あなたの場合、StringBuffer はこれらのメソッドをオーバーライドしないため、作成する各 StringBuffer インスタンスは異なります。つまり、new StringBuffer("abc") == new StringBuffer("abc") は false を返します。

なぜ誰かが StringBuffer をセットに追加するのか興味があります。

于 2013-07-04T05:39:14.580 に答える
1

ほとんどの変更可能なオブジェクトは、たまたま同じデータが含まれている場合、それらが同じであるとは想定していません。それらは可変であるため、いつでも内容を変更できます。つまり、現在は同じであるが後で同じである可能性がある、または現在は異なるが後で同じである可能性がある

ところで、StringBuilder がオプションの場合は、StringBuffer を使用しないでください。StringBuffer は 10 年以上前に置き換えられました。

于 2013-07-04T06:15:31.180 に答える
0

同じ引数を持っているにもかかわらず、2 つの StringBuffer オブジェクトは異なるオブジェクトです。したがって、HashSet は重複を無視する代わりに StringBuffers を追加するだけです。

于 2013-07-04T05:42:33.893 に答える
0

ハッシュ セットは「バケット」で機能します。ハッシュコードに従って、これらの「バケット」に値を格納します。equals(Object)メソッドを使用して、メンバーが等しいかどうかに応じて、「バケット」に複数のメンバーを含めることができます。

したがって、議論のために、10 個のバケットでハッシュ セットを構築し、それに整数 1、2、3、5、7、11、および 13 を追加するとします。int のハッシュ コードは単なる int です。最終的には次のようになります。

  • (空の)
  • 1、11
  • 2
  • 3、13
  • (空の)
  • 5
  • (空の)
  • 7
  • (空の)
  • (空の)

セットを使用する従来の方法は、メンバーがそのセットに含まれているかどうかを確認することです。ですから、「11 はこのセットに含まれていますか?」と言うと、ハッシュ セットは 11 を 10 でモジュロし、1 を取得して、2 番目のバケットを調べます (もちろん、バケットは 0 から開始しています)。

これにより、メンバーがセットに属しているかどうかを非常に迅速に確認できます。さらに11を追加すると、ハッシュ セットは既に存在するかどうかを確認します。その場合、再度追加することはありません。メソッドを使用してequals(Object)、もちろん 11 が 11 に等しいことを判断します。

「abc」のような文字列のハッシュ コードは、その文字列の文字によって異なります。重複する文字列「abc」を追加すると、ハッシュ セットは正しいバケットを検索し、equals(Object)メソッドを使用してメンバーが既に存在するかどうかを確認します。stringのequals(Object)メソッドも文字によって異なるため、"abc" は "abc" と同じです。

ただし、StringBuffer を使用する場合、各 StringBuffer にはオブジェクト ID に基づくハッシュ コードと等価性があります。equals(Object)基本メソッドとメソッドをオーバーライドしないhashCode()ため、すべての StringBuffer はハッシュ セットを別のオブジェクトのように見えます。それらは実際には重複していません。

StringBuffers を出力に出力するときは、StringBuffers で toString() メソッドを呼び出しています。これにより、重複した文字列のように見えるため、その出力が表示されます。

hashCode()これが、 をオーバーライドする場合にオーバーライドすることが非常に重要である理由でもありますequals(Object)。そうしないと、 Set が間違ったバケットにあるように見え、非常に奇妙で予測不可能な動作が発生します!

于 2013-07-04T05:55:58.887 に答える