Java 重写equals方法时,我们是否只使用';对象obj';作为参数?

Java 重写equals方法时,我们是否只使用';对象obj';作为参数?,java,overriding,equals,Java,Overriding,Equals,我的任务是: 在您的应用程序中适当地重写equals()和hashCode()方法 有理数类 它进一步扩展了。我的问题是,当重写equals方法时,是否更改传入的参数?如果它检查逻辑等价性,则我已完成以下操作: public boolean equals(Rational rhs){ if(this.num == rhs.num && this.denom == rhs.denom){ return true; } return false

我的任务是:

在您的应用程序中适当地重写equals()和hashCode()方法 有理数类

它进一步扩展了。我的问题是,当重写equals方法时,是否更改传入的参数?如果它检查逻辑等价性,则我已完成以下操作:

public boolean equals(Rational rhs){
    if(this.num == rhs.num && this.denom == rhs.denom){
        return true;
    }
    return false;
}
我不确定在重写该方法时这是否是一种方法。如果是,那么当您重写hashcode方法时,是否只是简单地挑选一段好的代码来分配hashcodes

此外,这是我创建的哈希代码。这样做对吗

@Override
public int hashCode(){
    int hc = 17;
    hc = 37 * hc + ((num == 0 && denom == 0) ? 0 : num);
    return 37 * hc + denom;


    //boolean b = cond ? boolExpr1 : boolExpr2;
    //if cond true then b=boolExpr1 else b=boolExpr2
}

您的
equals
方法不会覆盖
对象的
equals
。要覆盖它,参数必须是
对象

@Override
public boolean equals(Object other){
    if (!(other instanceof Rational))
        return false;
    Rational rhs = (Rational) other;
    if(this.num == rhs.num && this.denom == rhs.denom){
        return true;
    }
    return false;
}

请注意,
@Override
注释有助于检测您打算重写方法但却重载了该方法的情况。如果您将该注释放在原始方法中,您将得到一个编译错误,因为您的方法没有覆盖任何方法(假设您的
Rational
类没有扩展或实现包含
boolean equals(Rational rhs)
方法的某个类/接口).

但是您可以这样做,因为这不会覆盖
等于(对象)
您仍然需要这样做

public boolean equals(Object o) {
    return o instanceof Rational && equals((Rational) o);
}
调用
equals(Object)
的原因是您可能有许多不同类型的集合

List list = Arrays.asList(1, "Hello", new Rational(1, 2));
// needs to be able to compare with 1 and "Hello"
list.contains(new Rational(1, 2)); 

要正确重写一个方法—要在针对超类类型的引用调用该方法时“神奇地”调用重写方法—参数类型必须与超类中的参数类型完全相同

<> P>看看为什么会出现这种情况,考虑一下这里会发生什么:

Object r = new Rational();
boolean b = r.equals("x");
我们已经创建了一个对
Rational
的对象引用,这是允许我们做的,我们正在向
对象传递一个
String
。equals(Object)
方法,这也是允许我们做的,因为String是一个对象

如果你的覆盖成功了,你现在就有了一个
Rational
String
对象疯狂的引用!这将打破Java中的类型安全规则。通过强制您的参数为精确匹配,该语言可以确保方法中只出现“可接受”的参数

当然,为了使方法有效,现在需要一个强制显式地将“Obj'”ARG视为一个Rational:<代码> Rational RHS=(Rational)Objr;<代码>-您可能希望事先执行

instanceof
检查,以确保obj实际上是
Rational
,而不是其他类型(如字符串!)

一些值得理解的问题:

  • 在上面我们称之为
    r.equals(“x”)
    的情况下:您可能会想“编译器难道不能看到
    r
    实际上指向的是
    Rational
    ”?答案是“是”:Java只是选择不这样做。事实是,这是一个简单的例子来证明这一点。一般来说,为了保持一致性,引用类型的规则非常严格,而且通常,编译器无法“看到”这样的情况,比如
    Rational
    作为对象引用被传递到库方法中,或者是对象集合的成员
  • equals
    方法有一个中等复杂的契约,值得研究:您应该检查null,担心子类等会发生什么。我在上面使用
    instanceof
    是有争议的-
    getClass()==obj.getClass()
    可能更好。查查——约书亚·布洛赫(Joshua Bloch)的高效Java在这方面非常出色。或者读一下:
  • 有一种Java不支持的理论机制,称为“逆变参数覆盖”。这将允许
    myMethod(String)
    myMethod(Object)
    覆盖(即您可以使用一个更一般的参数-与您的情况相反),该参数始终是安全的,并且不会违反规则。但是它本身会导致问题,Java不支持它;请看下面的答案:
关于实现
hashCode()
方法的最后一个问题:在这样一个简单的类中,是的,通用hashCode方法应该可以。通常,将
等于
位设置正确是95%的工作


编辑:在更新的问题中,您提供了一个hashCode方法,该方法不。。。想了很多!您可以将其拆分为
return(31+num)*31+denom,或类似代码。我之所以使用31是因为:。

这是一个等于的重载,而不是覆盖。为了正确实现equals,它必须获得一个类型对象作为parameterOh,然后您将该对象转换为一个Rational,明白了。谢谢
if (obj instanceof Rational) {
    Rational r = (Rational)obj;
    ....