我想澄清一下我的理解是否正确:

==是一个引用比较,即两个对象都指向相同的内存位置 .equals()计算为对象中值的比较


当前回答

例1 -

==和.equals方法只用于引用比较。它表示两个对象是否引用同一个对象。

对象类等于方法实现

public class HelloWorld{
     public static void main(String []args){
       Object ob1 = new Object();
       Object ob2 = ob1;
       System.out.println(ob1 == ob2); // true
       System.out.println(ob1.equals(ob2)); // true
     }    
}

例2 -

但是如果我们想要使用equals方法比较对象的内容,那么class必须重写对象的类equals()方法并提供内容比较的实现。这里,String类重写了用于内容比较的equals方法。所有包装器类都覆盖了用于内容比较的equals方法。

字符串类等于方法实现

public class HelloWorld{
     public static void main(String []args){
       String ob1 = new String("Hi");
       String ob2 = new String("Hi");
       System.out.println(ob1 == ob2); // false (Both references are referring two different objects)
       System.out.println(ob1.equals(ob2)); // true
     }
}

例3 -

对于String,还有一个用例。在这里,当我们将任何字符串赋值给string引用时,字符串常量就会在string常量池中创建。如果将相同的字符串赋值给新的字符串引用,则不会创建新的字符串常量,而是引用现有的字符串常量。

public class HelloWorld{
     public static void main(String []args){
       String ob1 = "Hi";
       String ob2 = "Hi";
       System.out.println(ob1 == ob2); // true
       System.out.println(ob1.equals(ob2)); // true
     }
}

注意,每当重写hashCode方法时,通常都需要重写该方法,以便维护hashCode方法的一般契约,该契约规定相等的对象必须具有相等的散列码。

Java API equals()方法契约

其他回答

它是恒等和等价的区别。

A == b意味着A和b是相同的,也就是说,它们是内存中相同对象的符号。

A.equals (b)意味着它们是等价的,它们是在某种意义上具有相同值的对象的符号——尽管这些对象可能在内存中占据不同的位置。

注意,对于等价性,如何评估和比较对象的问题开始发挥作用——复杂的对象可能被认为是等效的,即使它们的一些内容不同。有了身份,就没有这样的问题了。

要在自定义类中使用equals函数,您必须重写equals函数(以及其他函数)。

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(芒果2)但它不等于identityHashCode(芒果3)

即使所有的字符串变量芒果,芒果2和芒果3都有相同的值,即“芒果”,identityHashCode()对所有变量仍然不相同。

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

我们知道如果hashcode(x)=N并且hashcode(y)=N => x等于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()通过。 如果我错了,请随意评论并让我知道。

下面是关系运算符==和方法.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类,我需要定义比较两个Person的标准。假设person类有身高和体重的实例变量。

因此,创建person对象person1和person2,并使用.equals()来比较这两个对象,我需要重写person类的equals方法,以定义基于哪个实例变量(高度或重量)的比较。

但是,==操作符仍然会根据两个对象(person1和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

只需记住.equals(…)必须由您试图比较的类实现。否则,就没有什么意义了;Object类的方法版本所做的事情与比较操作相同:

唯一需要对对象使用比较运算符的时候是比较枚举的时候。这是因为一次只有一个Enum值的实例。例如,给定枚举

enum FooEnum {A, B, C}

你永远不会同时拥有一个以上的A实例,对于B和c也是如此。这意味着你实际上可以像这样编写一个方法:

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

你就不会有任何问题了。