java中的Set永远不会允许重复,但它需要具有相同参数的StringBuffer对象.为什么?

Nit*_*esh 6 java set stringbuffer hashset

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); 
}
Run Code Online (Sandbox Code Playgroud)

输出:

[abc,abc,abc,abc]
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我添加StringBuffer("abc")了多次对象并Set添加了它,但Set从不添加重复项.

Mat*_*all 13

StringBuffer不会覆盖Object#equals()Object#hashCode(),这样的身份StringBuffer情况下是基于对缓冲区的内容,但在内存中的对象的地址.*


*该标识基于JLS不严格要求的内存中的地址,但是是典型Object#hashCode()实现的结果.来自JavaDoc:

尽管合理实用,但是由class定义的hashCode方法Object确实为不同的对象返回了不同的整数.(这通常通过将对象的内部地址转换为整数来实现,但Java™编程语言不需要此实现技术.)


Jon*_*eet 8

StringBuffer不会覆盖equalshashCode- 所以每个对象只等于它自己.

这是有意义的,因为StringBuffer非常"设计可变" - 当两个可变对象彼此相等时,相等可能导致问题,然后可以改变.将可变对象用作映射中的键或集合的一部分可能会导致问题.如果在插入集合后改变了一个,则会使集合中的条目无效,因为哈希代码可能会更改.例如,在地图中,您甚至无法使用与键相同的对象查找值,因为第一个测试是通过哈希码.

StringBuffer(和StringBuilder)被设计成非常短暂的对象 - 创建它们,附加到它们,将它们转换为字符串,然后你就完成了.每当你发现自己将它们添加到集合中时,你需要退一步看看它是否真的有意义.只是偶尔它可能会做,但通常只有当集合本身是短命的.

在覆盖时equals,你应该在自己的代码中考虑这个问题hashCode- 基于对象的任何可变方面,很少有好的想法.它使类更难以正确使用,并且很容易导致细微的错误,这可能需要很长时间来调试.


Sco*_*ion 1

您是否想到过在 StringBuffer 中看到 equals() 方法(或缺少该方法)?这就是你的答案。

Set 或任何基于散列的集合都取决于对象上的 equals() 和 hashcode() 方法公开的契约,以了解其行为特征。

在您的情况下,由于 StringBuffer 不会覆盖这些方法,您创建的每个 StringBuffer 实例都是不同的,即 new StringBuffer("abc") == new StringBuffer("abc") 将返回 false。

我很好奇为什么有人会将 StringBuffer 添加到集合中。