有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

在Java中使用==运算符进行对象比较

据我所知,==运算符用于引用比较,即两个对象是否指向相同的内存位置。 为了测试这一点,我创建了一个小型java程序,但结果并不一致。有人对此有任何线索吗

import java.util.HashSet;
import java.util.Set;

public class EqualOperatorTest {
    public static void main(String[] args) {
        boolean result;
        Employee employee1 = new Employee();
        employee1.setId(1);
        employee1.setName("XYZ");

        Employee employee2 = new Employee();
        employee2.setId(1);
        employee2.setName("XYZ");

        result = employee1.equals(employee2);
        System.out.println("Comparing two different Objects with equals() method: " + result);  //1. This returns True. Ok as we have overridden equals

        result = (employee1 == employee2);
        System.out.println("Comparing two different Objects with == operator: " + result);   //2. This returns False. Why? hashcode of both employee1 and employee2 are same but still == comparison returning false.

        //3. Validating hashcode of reference variables employee1 and employee2. We can see both has same hashcode (bcos we have overridden hashcode too in Employee class). But then why above employee1 == employee2 is returning false. Afterall == compares the memory location (or hashcode) and both have the same hashcodes,
        System.out.println("employee1 : " + employee1);   //employee1 and employee2 has same hashcode   
        System.out.println("employee2 : " + employee2);   //employee1 and employee2 has same hashcode   

        // Creating hashset and storing the same employee references.
        Set empSet = new HashSet();
        empSet.add(employee1);
        empSet.add(employee2);

        System.out.println(empSet);   //returns only one memory location(hashcode) as we have overridden hashcode in Employee class. Ok

        employee1 = employee2;      //Setting employee2 in employee1
        result = (employee1 == employee2);
        System.out.println("Comparing two reference pointing to same Object with == operator: " + result);  //This returns True. Ok 

    }
}

Need to understand why behavior of == operator is not same at 2 and 3.

我的Employee类很简单,有两个类级变量,它们是getter和setter,以及重写的equals和hashcode方法

public class Employee {
    private int id;
    private String name;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Employee other = (Employee) obj;
        if (id != other.id)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

共 (2) 个答案

  1. # 1 楼答案

    运算符==检查两个引用是否指向内存中的同一对象(对于诸如intdouble之类的基元类型,运算符==检查值是否相等)

    Employee a = new Employee(...); 
    Employee b = new Employee(...);
    
    System.out.println(a == b); // false
    System.out.println(b == a); // false
    System.out.println(a == a); // true
    System.out.println(b == a); // true
    
    Employee c = b;
    System.out.println(a == c); // the same as a == b
    System.out.println(b == c); // the same as b == b
    

    Object#equals(Object)检查两个对象的内容是否相同

    Employee a = new Employee(1, "XYZ");
    Employee b = new Employee(1, "XYZ");
    
    // if Employee#equals(Object); is overridden so that, 
    // it checks both id and name for equality 
    // then we can expect that all these lines returns true
    System.out.println(a.equals(b)); // true
    System.out.println(b.equals(a)); // true
    System.out.println(a.equals(a)); // true
    System.out.println(b.equals(b)); // true
    
    Employee c = b;
    System.out.println(a.equals(c)); // this is the same as a.equlas(b);
    
    Employee d = new Employee(2, "ABC");
    System.out.println(a.equals(d)); // false 
    

    Object#hashCode()返回标识内容的整数(如果两个对象相等,则哈希代码必须相同)

    Employee a = new Employee(1, "XYZ");
    Employee b = new Employee(1, "XYZ");
    
    System.out.println(a.hashCode() == b.hashCode());  // true expected since a and b are equal
    
    Employee c = b;
    System.out.println(a.hashCode() == c.hashCode()); // the same as a.hashCode() == b.hashCode()
    
    Employee d = new Employee(1, "xyz");
    // might be false, but can be true, 
    // it all depends on quality of hashCode() implementation
    System.out.println(a.hashCode() == d.hashCode()); 
    

    哈希代码用于基于哈希的数据结构中查找对象的指定索引,即存储对象的索引。假设Employee#hashCode()1, "XYZ"返回20。如果hashmap的基础数组的大小为11,则目标索引将为20 modulo 11;9)。因此,当您调用hashSet.contains(new Employee(1, "XYZ"));时,它将查看索引9。注意,完美散列函数为给定值返回总是唯一的数字并不存在也就是说,您的hashCode()实现也可能为属性值返回数字20"1, "xyz"(小写),这将导致相同的散列索引9。因此,在hashset在索引9处找到对象之后,它还必须执行相等性检查,以确保存储在索引9处的对象等于在contains(Object)中传递的对象

  2. # 2 楼答案

    关于==比较两个变量的引用这一事实,您是对的,但是,引用与哈希代码不同

    哈希代码是您编写的此方法返回的数字:

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + id;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    

    而引用是存储对象的内存位置。他们完全不同

    你有这种误解是可以理解的。如果没有重写hashCode,它将返回对象的内存位置,因此哈希代码将与内存位置相同。但是,由于您已经重写了hashCode,因此它们不再相同