".equals" 和 "==" 之间有什么区别?

67

今天我换了一位讲师,他给我介绍了一个奇怪的代码。他说最好使用.equals,当我问为什么时,他回答说“因为它是这样的!”

这里是一个例子:

if (o1.equals(o2))
{
 System.out.println("Both integer objects are the same");
}

与我过去所使用的不同:

if (o1 == o2)
{
  System.out.println("Both integer objects are the same");
}

.equals和==有什么区别?为什么使用.equals更好?

在快速搜索中找到这篇文章,但我无法理解那个答案:


这个问题已经被问了很多次。https://dev59.com/fHNA5IYBdhLWcg3wa9Gp - Kieran Senior
那我引用的答案包括 Java 和 C# 也是个好事情 :) - Kieran Senior
这提供了一个很好的概括回答。 - Mathee
2
没有任何一位讲师应该满足于给出这样的答案,你也不应该。 - user207421
.equals()是一个方法,而==是运算符。 - Rahul Raina
显示剩余2条评论
11个回答

113

在Java中,==总是仅比较两个引用(对于非原始类型),即测试这两个操作数是否引用同一对象。

但是,equals方法可以被重写 - 因此两个不同的对象仍然可能相等。

例如:

String x = "hello";
String y = new String(new char[] { 'h', 'e', 'l', 'l', 'o' });

System.out.println(x == y); // false
System.out.println(x.equals(y)); // true

此外,值得注意的是,任何两个相等的字符串常量(主要是字符串字面值,但也包括通过连接字符串常量形成的组合)最终会指向同一个字符串。例如:

String x = "hello";
String y = "he" + "llo";
System.out.println(x == y); // true!

这里的xy是对同一个字符串的引用,因为y是编译时常量,等于"hello"


1
关于非泛型类,如果没有重写equals方法,那么equals方法会与“==”相同,并且仅检查类的两个实例是否引用同一对象吗?谢谢。 - Numerator
3
是的。在类中,除非你覆盖 Equals 方法,否则它始终表示引用相等性。 - Jon Skeet
7
“@ingyhere”说,“对象”本身并没有指向任何东西。==是用来测试两个“引用”是否指向同一个对象的。如果你要抱怨“糟糕的用词”,那么你需要确保使用正确的术语。至于equals()是否比较对象状态——它可以,但不一定要这样做,也不会自动这样做。(而且它可能会考虑某些变量是否相等,但不考虑其他变量。) - Jon Skeet
3
我看不出那篇文章与此相关。那篇文章在讨论参数传递。比较的值恰好是引用。它们不一定是内存位置——它们可以是JVM想要用于引用的任何形式。引用类型变量的值就是一个引用,这就是为什么在这个上下文中,“==”是“引用相等运算符”。请参见Java语言规范的第15.21.3节:http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.21.3。这是非常明确定义的术语,我正在正确使用它们。 - Jon Skeet
2
@ingyhere:在许多情况下可以这样认为,但并非所有情况都是如此。这就是手挥之间的区别。当然可以实现一个JVM,其中引用值不是直接的内存位置,而是例如大型查找表中的条目。然而,您的观点似乎随着时间的推移而改变,从指责我错误地使用“引用”一词开始。您现在是否承认我使用“引用”一词完全符合JLS,并且正在比较的值确实是引用? - Jon Skeet
显示剩余4条评论

21

==运算符比较对象是否是同一个实例。equals()操作符比较对象的状态(例如,如果所有属性都相等)。您甚至可以重写equals()方法,以定义何时一个对象等于另一个对象。


9
注意, Object 类中的 equals() 方法的默认实现是回退到 this == other 的效果。这是一个常见的困惑来源,因为除非你使用一个实际上以有意义的方式实现了 equals() 方法的类,否则你看不出任何区别。 - Joachim Sauer
1
对,我应该提一下。提问者可以查看JDK本身,那里有许多他可以作为示例的类。 - Sylar

14
如果你和我各自走进银行,各开一个全新的账户,并存入100美元,那么:
  1. myAccount.equals(yourAccount) 返回 true,因为它们具有相同的值,但是
  2. myAccount == yourAccount 返回 false,因为它们不是同一个账户
(当然,假设Account类的定义是适当的。;-)

4
那将是一个非常糟糕的equals实现。 - user44242
5
这也是一个非常糟糕的==和equals之间区别的解释。 - jarnbjo
2
我喜欢这个比较,哈哈,它展示了为什么不应该使用==来比较字符串,因为错误的人可能会得到你的钱,或者你根本就拿不到钱。(谁会把钱存储为字符串呢,哈哈)但这是个好例子,能吓唬程序员。 - SSpoke

2

“==”是一个运算符。而equals方法则是Object类中定义的一个方法。

“==”用于检查两个对象在内存中是否具有相同的地址,对于原始类型,则检查它们是否具有相同的值。另一方面,equals方法检查被比较的两个对象是否具有相等的值(这取决于对象的equals方法如何实现)。equals方法不能应用于原始类型(这意味着如果a是一个原始类型,则不允许使用a.equals(someobject),但是someobject.equals(a)是可以的)。请注意保留HTML标签。


0

== 运算符比较两个对象引用,以检查它们是否引用同一实例。如果匹配成功,它也会返回 true。例如:

public class Example{
public static void main(String[] args){
String s1 = "Java";
String s2 = "Java";
String s3 = new string ("Java");
test(Sl == s2)     //true
test(s1 == s3)      //false
}}

上面的例子是引用比较,即两个对象指向同一内存位置。

String equals() 方法评估对象中的值进行比较。

   public class EqualsExample1{
   public static void main(String args[]){
   String s = "Hell";
   String s1 =new string( "Hello");
   String s2 =new string( "Hello");
   s1.equals(s2);    //true
    s.equals(s1) ;   //false
    }}

上面的例子比较了字符串的内容。如果字符串匹配,它将返回true,否则返回false。


-1
public static void main(String[] args){
        String s1 = new String("hello");
        String s2 = new String("hello");

        System.out.println(s1.equals(s2));
        ////
        System.out.println(s1 == s2);

    System.out.println("-----------------------------");

        String s3 = "hello";
        String s4 = "hello";

        System.out.println(s3.equals(s4));
        ////
        System.out.println(s3 == s4);
    }

在这个代码中,你可以比较 '==' 和 '.equals' 两者的不同。
其中,'.equals' 用于比较引用对象,而 '==' 则用于比较对象的状态。

你完全搞错了。 - user207421

-1
在Java中,当使用“==”操作符比较两个对象时,它会检查这些对象是否引用内存中的同一个位置。例如:
String obj1 = new String("xyz");
String obj2 = new String("xyz");
if(obj1 == obj2)
   System.out.println("obj1==obj2 is TRUE");
else
  System.out.println("obj1==obj2 is FALSE");

尽管这些字符串具有完全相同的字符(“xyz”),但上面的代码实际上会输出:obj1==obj2 is FALSE

Java String类实际上覆盖了Object类中默认的equals()实现 - 并且它重写了该方法,以便仅检查字符串的值,而不是它们在内存中的位置。这意味着如果您调用equals()方法来比较2个String对象,只要实际的字符序列相等,两个对象就被认为是相等的。

String obj1 = new String("xyz");
String obj2 = new String("xyz");
if(obj1.equals(obj2))
   System.out.printlln("obj1==obj2 is TRUE");
else
  System.out.println("obj1==obj2 is FALSE");

这段代码将输出以下内容:

obj1==obj2 为 TRUE


通常它会检查对象是否驻留在内存中的相同位置,但这是一种实现细节。并发垃圾收集器可以在对象的当前位置设置写入陷阱,将对象复制到新位置,然后更新一个引用以引用新副本,最后更新另一个引用。==运算符必须始终返回true,即使在两次更新之间,因为两个引用都标识相同的对象,但这并不意味着它们标识了相同的内存块。 - supercat

-2

equals()方法和==运算符执行两个不同的操作。equals()方法比较String对象内部的字符。==运算符比较两个对象引用,以查看它们是否引用同一实例。以下程序显示了两个不同的String对象可以包含相同的字符,但对这些对象的引用将不会比较为相等:

// equals() vs ==
class EqualsNotEqualTo {
     public static void main(String args[]) {
          String s1 = "Hello";
          String s2 = new String(s1);
          System.out.println(s1 + " equals " + s2 + " -> " +
          s1.equals(s2));
          System.out.println(s1 + " == " + s2 + " -> " + (s1 == s2));
     }
}

变量s1指的是由"Hello"创建的String实例。由s1初始化的对象被s2引用。因此,这两个String对象的内容相同,但它们是不同的对象。这意味着s1s2不引用相同的对象,因此它们不是==,正如前面示例的输出所示:
Hello equals Hello -> true
Hello == Hello -> false

1
这个问题实际上并没有涉及到字符串。虽然equals方法通常涉及到对象的“内部”,但它并不一定要这样做。许多对象的.equals()方法只使用内存地址(即相当于==)。 - Richard Tingle
1
在Java中,有少量的原始类型和一个“引用”类型。==运算符测试其操作数是否为相同的。由于引用类型的“值”是对象的标识,如果操作数引用同一对象,则它们才被视为相同。与对象本身无关;实际上,比较甚至不需要查看对象。 - supercat

-2

(1) == 可以应用于原始类型和对象类型,但equals()方法只能应用于对象类型。

(2) == 不能被覆盖用于内容比较,但equals方法可以被覆盖用于内容比较(例如:String类、包装类、集合类)。

(3) == 当尝试将其应用于异构类型时,==会产生不可比较类型的错误,而equals方法返回false。


-2

这里是关于你问题的简单解释:

==(等于)用于评估算术表达式

equals() 方法用于比较字符串

因此,对于数字操作最好使用 ==,对于字符串相关操作使用 equals() 方法。因此,对于对象的比较,equals() 方法是正确的选择。


1
问题中没有关于字符串的内容。 - user207421
1
@EJP,我刚试图解释“==”和“equals()”方法的含义。 - ersks

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