【问题标题】:equals() is not giving expected results [duplicate]equals() 没有给出预期的结果[重复]
【发布时间】:2018-08-27 11:21:58
【问题描述】:

我正在从事一个小项目,其中有国家、人口和大陆等类别。

Population 和 Continent 类都使用枚举来定义可能的值。我想在哪个国家/地区使用“工厂方法”来创建新国家/地区。代码如下:

public enum Continent {
    EUROPE, 
    ASIA, 
    AMERICA;
}

public enum Population {
    LOW(1000000),
    AVERAGE(2000000),
    HIGH(5000000); 
} 

public class Country{  

    private Continent=null;  
    private Population=null;

    Country(Continent continent, Population population){  
        this.continent=continent;  
        this.population=population;  
    }

好的,我的问题是我试图覆盖我的 equals() 函数,但它没有给我预期的结果。

public boolean equals(Country other){  
    if(this.population == other.population && this.continent==other.continent)
        return true;
    else 
        return false;  
}

但是断言测试给了我以下结果

java.lang.AssertionError: [new Country(Europe,HIGH)] Expecting:
等于:
但不是。

我在网上看,我发现当给定相同的参数时,它应该知道它是相同的,例如对于相同的参数,不应有两个不同的对象。我确定我是否理解正确,但它似乎是相关的。

我仍然不知道是否是这种情况以及如何处理它。想法?

更新:
在出现一些建议后,我尝试将 equals 函数更改为

public boolean equals(Country other){  
    if(this.population.equals(other.population) && this.continent.equals(other.continent))
        return true;
    else 
        return false;  
}

更新 2:

public boolean equals(Object o){  
    if(this.population.equals(o.population) && this.continent.equals(o.continent))
        return true;
    else 
        return false;  
}  

它不允许我做 .population.continent

【问题讨论】:

  • 这些要比较的对象是如何创建的?
  • 不要在人口上使用==,在那里也使用equals。并在人口对象上实现等于。当你使用==时,表示对象必须相同不相等。
  • equals的签名应该是'equals(Object o)' ??
  • @bilak 你可以在enum上使用==
  • @RobAu 你是对的,我没有意识到这是一个枚举

标签: java


【解决方案1】:

equals() 方法的签名错误

应该是:

  @Override
  public boolean equals(Object o) {

注意Object o 而不是Country

【讨论】:

  • 谢谢,我已经更新了问题。现在我无法检查他们是否属于同一大陆或同一人口
  • 您需要显式转换对象才能访问它的字段。您的代码不会像这样编译。
  • 好吧,我按照你说的修好了它,但我还是不明白。难道我也需要覆盖散列函数吗?我的意思是它似乎创建了两个保存在不同地方的罗马尼亚国家,但应该只有一个
  • 不,您有两个 Romania 实例,但使用相同的注释(如果操作正确)。这就是您需要equals 方法的原因。或者romania1 == romania2 会起作用。请也向我们展示您的测试结果。
【解决方案2】:

除了其他答案指出的签名更改外,您还需要检查参数是否为Country 类型。只有当它是你才能访问它的属性。下面的代码就是这样做的:

public boolean equals(Object o) {
    if(!(o instanceof Country))
         return false;
    Country c = (Country) o;
    if(this.population.equals(c.population) && this.continent.equals(c.continent))
        return true;
    return false;  
}

【讨论】:

  • 既然你总结了一切,我会选择你的答案作为最后一个。
【解决方案3】:

您缺少@Override 注释。另外,您不转发Country,而是转发Object

【讨论】:

  • 我不认为这是这里的关键。但我的原始代码中确实有它
  • 请注意关键,但注释会指出equals(Country) 未在超类中定义,因此无法覆盖
【解决方案4】:

一些面向对象编程的基础知识:

当你从一个类(例如Object)派生并且你想覆盖super类中的一个方法时,你需要匹配那个方法的签名。在您的情况下,您将覆盖 Object::equals,因此您需要匹配其签名。

正如@RobAu 所写,这是

public boolean equals (Object o)  

这反过来意味着您的编译器将不允许您使用访问子类的任何成员。这就是为什么您需要 (a) 检查参数的类并 (b) 对Country 进行硬转换。

作为替代方案,您可以使用 Lombok 之类的库,它会为您生成典型的 equals/hash 组合(请参阅 https://projectlombok.org/features/EqualsAndHashCode

编码愉快。

【讨论】:

    【解决方案5】:

    您应该在您的枚举中实现/覆盖equals,然后在您的方法中使用.equals 运算符来比较两个枚举。 此外,您忘记了 @Override 注释,因此永远不会调用此方法,因为不知道您是否已覆盖它。

    【讨论】:

    • @Override 虽然受到高度鼓励,但并不是必需的。使用它很好(在这种情况下,编译器会抛出一个错误,因为他没有覆盖正确的方法),但是如果 equals(Object obj) 被覆盖,它会工作,无论是否使用注释.
    • 这个方法永远不会被调用,因为不知道你已经覆盖了它。”这不是注释的工作方式,甚至不是它存在的原因。这个仅用于开发人员,我相信很容易指出一个方法被覆盖。注释@Override 是可选的
    • 但最初他没有覆盖正确的方法,所以使用它(就像每个人一样)会救他:)
    • 不要在枚举中使用equals。 Equals 消除了类型安全,并允许您错误地比较两种不同类型的枚举(这是无用的,因为它们总是返回 false)。 == 运算符使编译器保证您不会做傻事。相信我,我已经看到了脚和枪伤。 :)
    猜你喜欢
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    • 2019-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多