为什么此 Java 代码编译成功

Why this Java Code is compiling successfully

我没有重写很多 hashCode()equals() 方法所以我可能是错的 我的问题是最后一行

dep1.equals(emp2) 正在编译成功(为什么)(我期待编译错误,因为它们有不同的类型)并且在编译后我得到以下

15   15    false

我期望 15 15 true 因为我正在检查 equals 方法中的哈希码。

class Employee {
    private String name;
    private int id;

    public Employee(String name, int id) {
        this.name = name;
        this.id = id;
    }


    public int hashCode() {
        return this.id; 
    }

    public boolean equals(Employee employee) {
        return this.hashCode() == employee.hashCode();
    }


    public int getEmployeeId() {
        return this.id;
    }
}

class Department {
    private String name;
    private int id;

    public Department(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public int hashCode() {
        return this.id; 
    }

    public boolean equals(Department department) {
        return this.hashCode() == department.hashCode();
    }


    public int getDepartmentId() {
        return this.id;
    }
}


public class JavaCollections {
    public static void main(String args[]) {
        Employee emp2 = new Employee("Second Employee", 15);

        Department dep1 = new Department("Department One", 15);

        System.out.println(dep1.hashCode()+"  "+emp2.hashCode()+"  " + dep1.equals(emp2));
    }
}

那是因为 classes EmployeeDepartment 仍然没有重写方法 public boolean equals(Object obj) 继承自 Object class.

正是在 dep1.equals(emp2) 中调用了此方法,而不是 public boolean equals(Department department)

更具体地说,阅读JLS

An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true: ... The signature of mC is a subsignature (§8.4.2) of the signature of mA.

在这种情况下 boolean equals(Department department) 不是 boolean equals(Object obj).

子签名

首先说明为什么会这样编译:Java中的所有class类都继承自java.lang.Object, which defines equals(Object)方法,并提供了默认实现。这是您在比较 EmployeeDepartment 时调用的方法,而不是您提供的 重载 之一。

您的 equals 代码编译得很好,因为编译器不知道您认为您正在覆盖 equals 而实际上您并没有。编译器认为你想创建一个新方法

public boolean equals(Department department)

Department 个对象与其他 Department 个对象进行比较。

如果您编写的代码覆盖了 superclass 的方法,请向其添加 @Override 注释,如下所示:

@Override
public boolean equals(Department department)

现在编译器会正确地向您抱怨您的方法实际上并没有覆盖其基类中的方法 class,并在编译时提醒您注意该问题。

要修复您的代码,请更改 equals 的签名以采用 Object,添加 @Override,检查 null 和正确的类型,进行转换,然后进行实际比较:

@Override
public boolean equals(Department obj) {
    if (obj == null || !(obj instanceof Department)) {
        return false;
    }
    Department dept = (Department)obj
    return dept.id == id;
}

注:像这样实现equals

return this.hashCode() == department.hashCode();

非常脆弱。尽管它适用于您的情况,但当哈希码是对象的唯一 ID 时,当 hashCode 被其他实现替换时,这将无法在代码重构中幸存下来,例如,同时考虑 [=29 的实现=] 和 name。如果要依赖比较ID,直接比较ID,不用调用hashCode获取。

首先,此代码 dep1.equals(emp2) 调用对象 class.

的默认实现

其次,您没有覆盖您的两个 class 中的默认实现,因为您无法覆盖特定自定义类型的 equal 方法。

如果你需要你的答案是 15 15 true

替换

public boolean equals(Department department) {
        return this.hashCode() == department.hashCode();
    }

来自

@override
public boolean equals(Object department) {
        return this.hashCode() == department.hashCode();
    }