StringBuffer(StringBuilder)がHashSetにうまく入らない


やりたかったこと

単純に、StringBuffer型の文字列をHashSetに入れたかった

何がダメか

StringBuffer(StringBuilder)はequals()とhashCode()がOverrideされておらず、hashの比較がうまくいっていなかったため  

追記

StringBufferの場合

// StringBuffer
Set<StringBuffer> bufferSet = new HashSet<>();
StringBuffer sb = new StringBuffer("");

for (int i = 0; i < 10; i++){
   sb.setLength(0);
   sb.append("test" + i);
   bufferSet.add(sb);
}

bufferSet.forEach(s -> System.out.println(s));

//結果
test9

よく考えたら、同じObjectの中身を変更しているだけなので、当然の結果でした。
下記の内容は、合わせて調べた内容ですので参考程度に載せておきます。


StringBufferの場合は、Java.lang.Objectのequalsが利用されているため(下記)、Objectの比較のみです。

java.lang.Object.java
public boolean equals(Object obj) {
    return (this == obj);
}

以下の方が有用な例です。

Set<StringBuffer> sbSet = new HashSet<>();
sbSet.add(new StringBuffer("abc"));
sbSet.add(new StringBuffer("abc"));
sbSet.add(new StringBuffer("abc"));
sbSet.add(new StringBuffer("abc"));        

sbSet.forEach(s -> System.out.println(s));
//結果
abc
abc
abc
abc

Objectの比較のみであるので、中の文字列が同じでもイコール判定されない。

Stringの場合

// String
Set<String> stringSet = new HashSet<>();
String st = "";

for(int i = 0; i < 10; i++){
   st = "test" + i;
   stringSet.add(st);
}

stringSet.forEach(s -> System.out.println(s));
//結果
test4
test5
test2
test3
test8
test9
test6
test7
test0
test1

Stringは、毎回新しいObjectが生成されるため当然、Setに新しく入る。
ちなみにあまり関係ないですが、Stringのequalsは以下のようになっています。

java.lang.String.java
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
}

参考

A Set in java never allows duplicates, but it takes StringBuffer objects with the same argument. Why?