Java中==和equals()之间有什么区别?


622

我想澄清一下我是否正确理解了这一点:

  • == 是参考比较,即两个对象都指向相同的存储位置
  • .equals() 计算对象中值的比较

43
是的,差不多
John Kane

9
是的,当场。您可以将其.equals()视为有意义的等效对象
vikingsteve,2013年


19
诸如“两个对象都指向相同的存储位置”之类的句子是草率的语言,这会使理解变得更加困难。您的意思是:“两个变量都引用相同的对象”。注意,变量不是对象。变量是对对象的引用。对象不“指向”任何东西。
Jesper

Answers:


625

通常,您的问题的答案是“是”,但是...

  • .equals(...) 只会比较所写的内容进行比较,不会多也不会少。
  • 如果一个类没有覆盖equals方法,则默认为equals(Object o)覆盖了该方法的最接近的父类的方法。
  • 如果没有父类提供重写,则它默认为最终父类Object中的方法,因此您只能使用该Object#equals(Object o)方法。根据对象API,这与==; 也就是说,当且仅当两个变量都引用相同的对象且引用相同且相同时,它才返回true 。因此,您将测试对象相等性而不是功能相等性
  • hashCode如果您要进行覆盖,请务必记住覆盖,equals以免“违反合同”。根据API,如果hashCode()两个对象的方法显示等效,则从方法返回的结果必须相同equals。反过来并不一定是真的。

如果==检查内存引用,那么为什么我在[this] [1] [1]中得到这种奇怪的行为:docs.google.com/document/d/… 我希望输出为true。可以消除我的困惑
JPG

4
@JSK打印d1和d2的值,我想您会明白为什么返回false的原因。
BoDidely 2015年

2
@BoDidely我知道了。这是因为所有包装器类都是不可变的。
JPG

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).<br/> Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.docs.oracle.com/javase/7/docs/api/java/lang/…)–阿比耶耶
Abhijeet

无关:今天,我在评论低质量的新手问题时提出了一个关于好/有效/ ...“自动”消息的元问题(meta.stackoverflow.com/questions/372795/…)。我收到的反馈几乎感觉到“您正在做完全错误的事情”。现在我只是想知道您如何看待?在箭袋中是否有“通用”消息,或者在这种情况下仅写特定注释?
GhostCat

107

关于String类:

equals()方法比较String实例内部(在堆上)的“值”,而不管两个对象引用是否引用相同的String实例。如果任何两个String类型的对象引用都引用同一个String实例,那就太好了!如果两个对象引用引用两个不同的String实例,则不会有任何区别。它是要比较的每个String实例内部的“值”(即:字符数组的内容)。

另一方面,“ ==” 运算符比较两个对象引用的值,以查看它们是否引用相同的String实例。如果两个对象的值引用“引用”相同的String实例,则布尔表达式的结果将为“ true” .. duh。另一方面,如果两个对象引用的值“引用” 不同的String实例(即使两个String实例都具有相同的“值”,即每个String实例的字符数组的内容相同),则布尔表达式的结果将为“ false”。

与任何解释一样,让它沉入。

我希望这可以使事情变得顺利。


1
所以对于字符串==引用也等于吗?即与其他对象一样工作?
JonnyRaa 2014年

2
(螺纹巫术,我知道...)为StringS,==是参考值等于为好,是的,但它通常工作(如两个Strings的相同内容将通常==对方),因为如何Java的手柄String秒。并非总是如此,这当然是不好的做法,但这是一个普遍的错误,特别是来自其他语言的人。
Tonio 2014年

7
添加到Tonio的评论中。String从字符串文字开始构建将被添加到String constant pool,例如String s1 = "someString"; String s2 = "someString;"s1s2将共享相同的引用。 s1 == s2将返回true。但是,如果它们是通过构造的String constructorString s1 = new String("someString"); String s2 = new String("someString");则它们将不会共享相同的引用。s1 == s2将返回false。
加文

61

根据您是在谈论“原始”还是“对象类型”,存在一些细微的差异。如果您谈论的是“静态”或“非静态”成员,也可以这样说;您也可以混合以上所有内容...

这是一个示例(您可以运行它):

public final class MyEqualityTest
{
    public static void main( String args[] )
    {
        String s1 = new String( "Test" );
        String s2 = new String( "Test" );

        System.out.println( "\n1 - PRIMITIVES ");
        System.out.println( s1 == s2 ); // false
        System.out.println( s1.equals( s2 )); // true

        A a1 = new A();
        A a2 = new A();

        System.out.println( "\n2 - OBJECT TYPES / STATIC VARIABLE" );
        System.out.println( a1 == a2 ); // false
        System.out.println( a1.s == a2.s ); // true
        System.out.println( a1.s.equals( a2.s ) ); // true

        B b1 = new B();
        B b2 = new B();

        System.out.println( "\n3 - OBJECT TYPES / NON-STATIC VARIABLE" );
        System.out.println( b1 == b2 ); // false
        System.out.println( b1.getS() == b2.getS() ); // false
        System.out.println( b1.getS().equals( b2.getS() ) ); // true
    }
}

final class A
{
    // static
    public static String s;
    A()
    {
        this.s = new String( "aTest" );
    }
}

final class B
{
    private String s;
    B()
    {
        this.s = new String( "aTest" );
    }

    public String getS()
    {
        return s;
    }

}

您可以通过以下链接比较“ ==“(等于运算符)和“ .equals(...)”(java.lang.Object类中的方法)的解释:


2
有趣的例子。从以上答案的不同角度来看。谢谢!
安德鲁(Andrew)

1
我认为是最佳答案,因为它比其他全文答案更清晰,而且不会丢失说明(当然,如果您理解课堂和静态概念)
Carrm

44

==和equals之间的差异使我困惑了一段时间,直到我决定仔细研究一下。他们中的许多人说,比较字符串时应该使用equals而不是==。希望在这个答案中我能够说出区别。

回答此问题的最佳方法是对自己问一些问题。因此,让我们开始:

以下程序的输出是什么:

String mango = "mango";
String mango2 = "mango";
System.out.println(mango != mango2);
System.out.println(mango == mango2);

如果你说,

false
true

我会说你是对的,你为什么这么说呢?如果您说输出是,

true
false

我会说你错了,但我仍然会问你,为什么你认为那是对的?

好的,让我们尝试回答这个问题:

以下程序的输出是什么:

String mango = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango3);
System.out.println(mango == mango3);

现在,如果你说,

false
true

我会说你错了,但是为什么现在错了?该程序的正确输出是

true
false

请比较上面的程序并尝试考虑一下。

好。现在这可能会有所帮助(请阅读:打印对象的地址 -不可能,但是我们仍然可以使用它。)

String mango = "mango";
String mango2 = "mango";
String mango3 = new String("mango");
System.out.println(mango != mango2);
System.out.println(mango == mango2);
System.out.println(mango3 != mango2);
System.out.println(mango3 == mango2);
// mango2 = "mang";
System.out.println(mango+" "+ mango2);
System.out.println(mango != mango2);
System.out.println(mango == mango2);

System.out.println(System.identityHashCode(mango));
System.out.println(System.identityHashCode(mango2));
System.out.println(System.identityHashCode(mango3));

您是否可以尝试考虑上面代码中的最后三行的输出:对我而言,ideone可以将其打印出来(您可以在此处查看代码):

false
true
true
false
mango mango
false
true
17225372
17225372
5433634

哦! 现在您看到identityHashCode(mango)等于identityHashCode(mango2),但不等于identityHashCode(mango3)

即使所有字符串变量-mango,mango2和mango3-都具有相同的值,即“ mango”,identityHashCode()但对于所有变量而言仍然不相同。

现在尝试取消注释此行// mango2 = "mang";,然后再次运行它,这一次您将看到所有三个identityHashCode()都不相同。嗯,这是个有用的提示

我们知道if hashcode(x)=Nhashcode(y)=N=>x is equal to y

我不确定java在内部如何工作,但是我想这就是我说的时候发生的事情:

mango = "mango";

Java创建了一个字符串"mango",该字符串由mango类似这样的变量指向(引用)

mango ----> "mango"

现在在下一行中,当我说:

mango2 = "mango";

它实际上重用了"mango"看起来像这样的相同字符串

mango ----> "mango" <---- mango2

mango和mango2都指向同一参考现在,当我说

mango3 = new String("mango")

实际上,它为“ mango”创建了一个全新的引用(字符串)。看起来像这样

mango -----> "mango" <------ mango2

mango3 ------> "mango"

这就是为什么当我提出其价值时mango == mango2,它提出了true。当我为分配值时mango3 == mango2,它false也会输出(即使值相同)。

当您取消注释该行时,// mango2 = "mang"; 它实际上创建了一个字符串“ mang”,从而使我们的图形变为:

mango ---->"mango"
mango2 ----> "mang"
mango3 -----> "mango"

这就是为什么identityHashCode对于所有人而言都不相同的原因。

希望这对你们有帮助。实际上,我想生成一个==失败且equals()通过的测试用例。请随时发表评论,如果我错了,请通知我。


是否mango == mango2会发生,因为你没有创建mango2 一个新的String对象,而不仅仅是直接引用"mango"
brt

1
使用String清除对==和equals的疑问的错误示例,将不与new一起使用时的String放入String Pool,并且每当将相同的字符串分配给新引用时,它将指向pool中的相同字符串。因此,可能使用一些自定义对象示例进行==和.equals()比较。
om252345

30

==操作符测试两个变量是否有(内存地址也称为指针)相同的标记

String foo = new String("abc");
String bar = new String("abc");

if(foo==bar)
// False (The objects are not the same)

bar = foo;

if(foo==bar)
// True (Now the objects are the same)

equals()方法测试两个变量是否引用具有相同状态(值)的对象

String foo = new String("abc");
String bar = new String("abc");

if(foo.equals(bar))
// True (The objects are identical but not same)

欢呼声:-)


1
错误。if(foo == bar)这应该为true而不是false。它将重用相同的字符串“ adc”。在沙箱中对其进行测试,对于两者都将返回true。
约翰·洛根

2
@JohnathanLogan我猜它是由于字符串实习。现在,我已更改为“ new String(“ abc”)“。希望现在不会有任何问题。感谢您的通知。
Mohanraj Balasubramaniam

13

您将必须重写equals函数(以及其他函数),以将其与自定义类一起使用。

equals方法比较对象。

==二进制运算符比较的内存地址。


8

如果您不重写.equals(),则==和.equals()都引用同一对象。

重写.equals()后,您希望执行的操作是您的愿望。您可以将调用对象的状态与传入对象的状态进行比较,也可以只调用super.equals()


7

==是一个运算符equals()是一个方法

运算符通常用于原始类型比较,因此==用于内存地址比较,equals()方法用于比较对象


6
 String w1 ="Sarat";
 String w2 ="Sarat";
 String w3 = new String("Sarat");

 System.out.println(w1.hashCode());   //3254818
 System.out.println(w2.hashCode());   //3254818
 System.out.println(w3.hashCode());   //3254818

 System.out.println(System.identityHashCode(w1)); //prints 705927765
 System.out.println(System.identityHashCode(w2)); //prints 705927765
 System.out.println(System.identityHashCode(w3)); //prints 366712642


 if(w1==w2)   //  (705927765==705927765)
 {
   System.out.println("true");
 }
 else
 {
   System.out.println("false");
 }
 //prints true

 if(w2==w3)   //  (705927765==366712642)
 {
   System.out.println("true");
 }
 else
 {
   System.out.println("false");
 }
 //prints false


 if(w2.equals(w3))   //  (Content of 705927765== Content of 366712642)
 {
   System.out.println("true");
 }
 else
 {
   System.out.println("false");
 }
 //prints true

简单而最佳的解释
Sritam Jagadev

5

请记住,.equals(...)必须由您要比较的类来实现。否则,没有什么意义。Object类方法的版本与比较操作的作用相同:Object#equals

真正要对对象使用比较运算符的唯一时间是在比较枚举时。这是因为一次仅存在一个Enum值实例。例如,给定枚举

enum FooEnum {A, B, C}

你将永远不会有多个实例A的时间,与同为BC。这意味着您实际上可以编写如下方法:

public boolean compareFoos(FooEnum x, FooEnum y)
{
    return (x == y);
}

而且您将没有任何问题。


4

在评估代码时,很明显(==)根据内存地址进行比较,而equals(Object o)比较实例的hashCode()。这就是为什么如果您以后不感到意外的话,请说不要破坏equals()和hashCode()之间的约定。

    String s1 = new String("Ali");
    String s2 = new String("Veli");
    String s3 = new String("Ali");

    System.out.println(s1.hashCode());
    System.out.println(s2.hashCode());
    System.out.println(s3.hashCode());


    System.out.println("(s1==s2):" + (s1 == s2));
    System.out.println("(s1==s3):" + (s1 == s3));


    System.out.println("s1.equals(s2):" + (s1.equals(s2)));
    System.out.println("s1.equal(s3):" + (s1.equals(s3)));


    /*Output 
    96670     
    3615852
    96670
    (s1==s2):false
    (s1==s3):false
    s1.equals(s2):false
    s1.equal(s3):true
    */

4

这是relational operator ==和之间的区别的一般规则the method .equals()

object1 == object2比较object1和object2引用的对象是否引用了Heap中的相同内存位置

object1.equals(object2)比较object1和object2的值,而不管它们在内存中的位置

使用String可以很好地证明这一点

场景1

 public class Conditionals {

    public static void main(String[] args) {
       String str1 = "Hello";
       String str2 = new String("Hello");
       System.out.println("is str1 == str2 ? " + (str1 == str2 ));
       System.out.println("is str1.equals(str2) ? " + (str1.equals(str2 )));
    }

 }



The result is
      is str1 == str2 ? false
      is str1.equals(str2) ? true 

方案2

public class Conditionals {

    public static void main(String[] args) {
       String str1 = "Hello";
       String str2 = "Hello";
       System.out.println("is str1 == str2 ? " + (str1 == str2 ));
       System.out.println("is str1.equals(str2) ? " + (str1.equals(str2 )));
    }

}

The result is 
  is str1 == str2 ? true
  is str1.equals(str2) ? true

此字符串比较可用作比较其他类型对象的基础。

例如,如果我有一个Person类,则需要定义比较两个人的标准。假设此人类具有身高和体重的实例变量。

因此,创建人员对象person1 and person2并使用.equals()I 来比较这两个对象,我需要重写人员类equals方法以根据比较的实例变量(高或重)来定义。

但是,== operator will still return results based on the memory location of the two objects(person1 and person2)

为了便于概括此人员对象比较,我创建了以下测试类。对这些概念进行试验将揭示大量事实

package com.tadtab.CS5044;

public class Person {

private double height;
private double weight;

public double getHeight() {
    return height;
}

public void setHeight(double height) {
    this.height = height;
}

public double getWeight() {
    return weight;
}

public void setWeight(double weight) {
    this.weight = weight;
}


@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    long temp;
    temp = Double.doubleToLongBits(height);
    result = prime * result + (int) (temp ^ (temp >>> 32));
    return result;
}

@Override
/**
 * This method uses the height as a means of comparing person objects.
 * NOTE: weight is not part of the comparison criteria
 */
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Person other = (Person) obj;
    if (Double.doubleToLongBits(height) != Double.doubleToLongBits(other.height))
        return false;
    return true;
}

public static void main(String[] args) {

    Person person1 = new Person();
    person1.setHeight(5.50);
    person1.setWeight(140.00);

    Person person2 = new Person();
    person2.setHeight(5.70);
    person2.setWeight(160.00);

    Person person3 = new Person();
    person3 = person2;

    Person person4 = new Person();
    person4.setHeight(5.70);

    Person person5 = new Person();
    person5.setWeight(160.00);

    System.out.println("is person1 == person2 ? " + (person1 == person2)); // false;
    System.out.println("is person2 == person3 ? " + (person2 == person3)); // true 
    //this is because perosn3 and person to refer to the one person object in memory. They are aliases;
    System.out.println("is person2.equals(person3) ? " + (person2.equals(person3))); // true;

    System.out.println("is person2.equals(person4) ? " + (person2.equals(person4))); // true;

    // even if the person2 and person5 have the same weight, they are not equal.
    // it is because their height is different
    System.out.println("is person2.equals(person4) ? " + (person2.equals(person5))); // false;
}

}

该类执行的结果是:

is person1 == person2 ? false
is person2 == person3 ? true
is person2.equals(person3) ? true
is person2.equals(person4) ? true
is person2.equals(person4) ? false

3

还要注意,.equals()通常包含==用于测试的内容,因为如果要测试两个对象是否相等,这是您要测试的第一件事。

==确实查看原始类型的值,并检查对象的引用。


3

==运算符总是比较参考。但是在

equals()方法

如果我们覆盖了equals方法,则取决于实现,而不是根据覆盖方法中给出的实现基础比较对象。

 class A
 {
   int id;
   String str;

     public A(int id,String str)
     {
       this.id=id;
       this.str=str;
     }

    public static void main(String arg[])
    {
      A obj=new A(101,"sam");
      A obj1=new A(101,"sam");

      obj.equals(obj1)//fasle
      obj==obj1 // fasle
    }
 }

在上面的代码中,obj和obj1对象都包含相同的数据,但是引用不相同,因此等于return false和==也。但是如果我们覆盖等于方法,则

 class A
 {
   int id;
   String str;

     public A(int id,String str)
     {
       this.id=id;
       this.str=str;
     }
    public boolean equals(Object obj)
    {
       A a1=(A)obj;
      return this.id==a1.id;
    }

    public static void main(String arg[])
    {
      A obj=new A(101,"sam");
      A obj1=new A(101,"sam");

      obj.equals(obj1)//true
      obj==obj1 // fasle
    }
 }

知道签出它只会在相同情况下返回true和false

等于方法。

它根据对象的content(id)比较对象

但是==

仍然比较对象的引用。


3

==和equals()之间的主要区别是

1)==用于比较基元。

例如 :

        String string1 = "Ravi";
        String string2 = "Ravi";
        String string3 = new String("Ravi");
        String string4 = new String("Prakash");

        System.out.println(string1 == string2); // true because same reference in string pool
        System.out.println(string1 == string3); // false

2)equals()用于比较对象。例如 :

        System.out.println(string1.equals(string2)); // true equals() comparison of values in the objects
        System.out.println(string1.equals(string3)); // true
        System.out.println(string1.equals(string4)); // false

2

==可以用于许多对象类型,但是可以Object.equals用于任何类型,尤其是字符串和Google Map Markers。


2
public class StringPool {

public static void main(String[] args) {

    String s1 = "Cat";// will create reference in string pool of heap memory
    String s2 = "Cat";
    String s3 = new String("Cat");//will create a object in heap memory

    // Using == will give us true because same reference in string pool

    if (s1 == s2) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }

    // Using == with reference and Object will give us False

    if (s1 == s3) {
        System.out.println("true");
    } else {
        System.out.println("false");
    }

    // Using .equals method which refers to value

    if (s1.equals(s3)) {
        System.out.println("true");
    } else {
        System.out.println("False");
    }

    }
  }

----输出----- true false true


2

可能值得补充的是,对于原始类型的包装对象-即Int,Long,Double-如果两个值相等,则==将返回true。

Long a = 10L;
Long b = 10L;

if (a == b) {
    System.out.println("Wrapped primitives behave like values");
}

相比之下,将上述两个Long放入两个单独的ArrayList中,等于将它们视为相同,但==则不然。

ArrayList<Long> c = new ArrayList<>();
ArrayList<Long> d = new ArrayList<>();

c.add(a);
d.add(b);
if (c == d) System.out.println("No way!");
if (c.equals(d)) System.out.println("Yes, this is true.");

即使两个值相等,原始类型(即Integer,Long,Double ==)的包装对象也可能不会返回true。它完全取决于包装器的缓存。下面的代码将打印假的,因为默认的缓存被限制在-128到127 Long a = 128l; Long b = 128l; System.out.println(a == b);
Neetesh巴德瓦杰

1

字符串池(又名实习)和整数池模糊的差异进一步,并可能允许您使用==在某些情况下为对象,而不是的.equals

这样可以提高性能(?),但会增加复杂性。

例如:

assert "ab" == "a" + "b";

Integer i = 1;
Integer j = i;
assert i == j;

复杂性的权衡:以下可能会让您感到惊讶:

assert new String("a") != new String("a");

Integer i = 128;
Integer j = 128;
assert i != j;

我建议你从这样的微型优化走就走,并且始终使用.equals的对象,并==为原语:

assert (new String("a")).equals(new String("a"));

Integer i = 128;
Integer j = 128;
assert i.equals(j);

1

简而言之,答案是“是”。

在Java中,==操作员比较两个对象以查看它们是否指向相同的内存位置;而该.equals()方法实际上是比较两个对象以查看它们是否具有相同的对象值。


0

基本上,==比较两个对象在堆上是否具有相同的引用,因此,除非两个引用链接到同一对象,否则此比较将为false。

equals()是从Object类继承的方法。默认情况下,此方法比较两个对象是否具有相同的引用。它的意思是:

object1.equals(object2) <=> object1 == object2

但是,如果要在同一类的两个对象之间建立相等性,则应重写此方法。hashCode()如果您已重写,则重写方法也非常重要equals()

实施hashCode()时确立平等是Java对象合同的一部分。如果您正在使用集合,但是尚未实现hashCode(),可能会发生奇怪的坏事:

HashMap<Cat, String> cats = new HashMap<>();
Cat cat = new Cat("molly");
cats.put(cat, "This is a cool cat");
System.out.println(cats.get(new Cat("molly"));

null如果尚未实现,将在执行上一个代码后打印出来hashCode()


0

由于Java不支持运算符重载,因此==对于每个对象的行为都相同,但是equals()是方法,可以在Java中重写该方法,并且可以根据业务规则更改比较对象的逻辑。

Java中==和equals之间的主要区别在于,“ ==”用于比较基元,而建议使用equals()方法检查对象的相等性。

字符串比较是同时使用==和equals方法的常见方案。由于java.lang.String类重写equals方法,所以如果两个String对象包含相同的内容,则返回true,但是只有两个引用指向相同的对象时,==才返回true。

这是使用==和equals()方法比较Java中的两个String是否相等的示例,这将消除一些疑问:

public class TEstT{

    public static void main(String[] args) {

String text1 = new String("apple");
String text2 = new String("apple");

//since two strings are different object result should be false
boolean result = text1 == text2;
System.out.println("Comparing two strings with == operator: " + result);

//since strings contains same content , equals() should return true
result = text1.equals(text2);
System.out.println("Comparing two Strings with same content using equals method: " + result);

text2 = text1;
//since both text2 and text1d reference variable are pointing to same object
//"==" should return true
result = (text1 == text2);
System.out.println("Comparing two reference pointing to same String with == operator: " + result);

}
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.