StringBuilder .equals Java

34
class strb
{

    static public void main(String...string)
    {
         StringBuilder s1 = new StringBuilder("Test");
         StringBuilder s2 = new StringBuilder("Test");

         System.out.println(s1); // output: Test
         System.out.println(s2); // Test
         System.out.println(s1==s2); // false
         System.out.println(s1.equals(s2)); //Line 1 output: false
         System.out.println(s1.toString()==s2.toString()); //Line 2 output: false
    }

}

关于 .equals 我有一个简短的问题:

无论对象内容如何,只有当对象引用指向同一个对象时,.equals 方法才返回 true 吗?


编辑: 现在我明白了关于 .equals 的部分,但为什么第二行不返回 true 呢?

编辑: 我认为 == 查看的是引用变量的地址,所以 s1 和 s2 不能相等。如果我的假设不正确,请纠正我。


2
请查看此帖子 https://dev59.com/zGgu5IYBdhLWcg3wv5Ya 和 https://dev59.com/pmgu5IYBdhLWcg3w4625 - krishnakumarp
10个回答

67
是的,StringBuilder没有覆盖Object的.equals()函数,这意味着两个对象引用不相同,结果为false。
对于StringBuilder,你可以使用s1.toString().equals(s2.toString())。
对于你的编辑,你正在对两个不同的String对象调用==运算符。==运算符会返回false,因为对象不同。要比较字符串,你需要使用String.equals()或String.equalsIgnoreCase()。
这是你之前遇到的同样的问题。

1
你知道为什么StringBuilder没有重写equals()方法吗?这似乎很奇怪。 - Algorithmist
7
基本上,如果我猜的话,如果你有两个StringBuilder,你更有可能测试它们是否是同一个StringBuilder在构建你的字符串,而不是两个不同的构建器构建相同的字符串。我想不出有多少情况下会有两个不同的实例化的StringBuilders在构建同一件事情。 - hotforfeature
1
关于你的第一句话,我认为“==”测试引用,“.equals()”测试对象值? - user5813538
我认为 StringBuilder() 只能比较对象的值,仅此而已! - milad salimi

4

StringBuilder类没有提供重载的equals()方法。因此,当对StringBuilder的实例调用该方法时,会执行Object类中该方法的实现,因为StringBuilder extends Object

源代码如下:

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

这只是简单地比较引用的相等性。


3
.equals方法在Object类中的默认实现就如你所提到的。
其他的类可以覆盖这种行为,但是StringBuilder不是其中之一。 String则是可以覆盖的,它会确保两个对象的字符串表示结果相同。具体请参考String API文档。
如果有疑问,请参考相关对象的文档资料。

2

检查equals方法的合同:

它必须是一致的(如果对象没有被修改,那么它必须保持返回相同的值)。

这就是为什么StringBuilder不管其内容如何都不会覆盖它的原因。

让我们以上面的例子为例。

     StringBuilder s1 = new StringBuilder("Test");
     StringBuilder s2 = new StringBuilder("Test");

也许你期望 s1.equals(s2) 返回 true,因为当前运行时的值相同。
但是如果你添加一行代码呢?
    s1.append("abc");

那么s1和s2将有不同的字符串内容,s1.equals(s2)预计为false。但这与一致性相矛盾。


"检查equals方法的契约"。对于为什么StringBuilder不实现.equals()提供了出色的解释。非常好的答案。 - Jonathan E. Landrum
很抱歉,但这仍然违反了最小惊讶原则。看看你对章程的解释:“如果对象没有被修改”。那么对象确实被修改了。equals()方法的目标是评估两个对象的功能等价性。“一致性”,根据您的评估,永远不会被任何对象违反,因为没有对象(可变或不可变)会落入该类别。当对象发生突变时(例如.append()),equals()的契约应始终反映内容更改。 - alife

2

对于你的第一个答案,请查看@abmitchell的回答。

关于你的编辑:

在Java中,String是一个对象,我们不能使用==来比较对象的值相等。

==用于比较原始值或对象引用。

要比较对象值,我们在Java中使用equals()


1

StringBuilderStringBuffer 没有重写 Object 类的 equals 函数,但是字符串重写了 equals 方法。 Object 的函数如下:

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

你可以像这样编写你的代码。
System.out.println(s1.toString() == s2.toString());
System.out.println(s1.toString().equals(s2.toString()));

1

StringBuilder 类没有像 String 类一样实现 equals() 方法。

所以它执行默认的 Object 类功能,再次仅检查地址相等性,在这种情况下不同。因此它打印 false。

注 1:您也可以在对象上使用 == 运算符,但它只是检查两个对象的地址是否相同。

注 2:在比较在字符串常量池中创建的两个 String 对象时,== 运算符发挥了很好的作用,以找出它是否真的在字符串常量池中创建了一个新的对象。


0

同意以上两个回复,但值得注意的是,实际上可以比较内容:

System.out.println(s1.toString().equals(s2.toString())); //Line 1

0

正如其他人所说,StringBuilder没有覆盖equals方法。但是,它实现了Comparable接口(自Java 11起)。因此,您可以检查s1.compareTo(s2) == 0来判断字符串表示是否相等。


0

由于StringBuilder没有equals方法,最好先将StringBuilder转换为String,然后再检查相等性。例如 - sb1.toString().equals(sb2.toString())

注意:在这里,==运算符或sb1 == sb2永远不起作用,因为两个StringBuilder是完全不同的对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接