覆盖java equals()方法 - 不工作?

Jos*_*ton 150 java overriding equals

我遇到了一个有趣(而且非常令人沮丧)的问题,equals()今天的方法导致了我认为是经过良好测试的类崩溃并导致我花了很长时间才能追踪的错误.

为了完整起见,我没有使用IDE或调试器 - 只是老式的文本编辑器和System.out.时间非常有限,这是一个学校项目.

无论如何 -

我开发一个基本的购物车可能包含ArrayListBook对象.为了贯彻落实addBook(),removeBook()以及hasBook()对车的方法,我想检查是否Book已在存在Cart.我走了 -

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}
Run Code Online (Sandbox Code Playgroud)

一切都在测试中运行良好.我创建了6个对象并用数据填充它们.做了很多添加,删除,has()操作Cart,一切正常.我读到你可以拥有equals(TYPE var)或者equals(Object o) { (CAST) var }假设因为它有效,所以没关系太多.

然后我遇到了一个问题 - 我需要在Book类中创建一个包含它的Book对象.不会输入任何其他数据.基本上如下:ID

public boolean hasBook(int i) {
    Book b = new Book(i);
    return hasBook(b);
}

public boolean hasBook(Book b) {
    // .. more code here
    return this.books.contains(b);
}
Run Code Online (Sandbox Code Playgroud)

突然间,该equals(Book b)方法不再有效.这需要花费很长时间才能在没有良好调试器的情况下进行跟踪,并假设Cart该类已经过适当的测试和更正.将equals()方法交换到以下内容后:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}
Run Code Online (Sandbox Code Playgroud)

一切都开始了.有没有理由该方法决定不采用Book参数,即使它显然一个Book对象?唯一的区别似乎是它是在同一个类中实例化的,并且只填充了一个数据成员.我很困惑.请揭开一些光明?

jjn*_*guy 326

在Java中,equals()继承的方法Object是:

public boolean equals(Object other);
Run Code Online (Sandbox Code Playgroud)

换句话说,参数必须是类型Object.

ArrayList使用正确的equals方法,在那里你总是调用一个没有适当覆盖Object的平等.

不正确覆盖方法可能会导致问题.

我每次都重写等于以下内容:

@Override
public boolean equals(Object other){
    if (other == null) return false;
    if (other == this) return true;
    if (!(other instanceof MyClass))return false;
    MyClass otherMyClass = (MyClass)other;
    ...test other properties here...
}
Run Code Online (Sandbox Code Playgroud)

使用@Override注释可以帮助减轻愚蠢的错误.

只要您认为自己覆盖了超类或接口的方法,就可以使用它.这样,如果你做错了,你将收到编译错误.

  • 这是支持@Override注释的一个很好的论据......如果OP使用@Override,他的编译器会告诉他他实际上并没有覆盖父类方法...... (31认同)
  • 使用instanceof时,先前的nullcheck是多余的. (19认同)
  • 某些IDE(例如Eclipse)甚至可以根据类成员变量为您自动生成equals()和hashcode()方法. (5认同)

小智 109

如果您使用eclipse,请转到顶部菜单

Source - >生成equals()和hashCode()

  • 在IntelliJ中,您可以在Code→Generate ...或control + N下找到它.:) (16认同)
  • 我希望我能给出这个答案10个赞成票. (7认同)

小智 11

对你的问题稍微偏离主题,但无论如何它可能值得一提:

Commons Lang有一些很好的方法可以用来覆盖equals和hashcode.查看EqualsBuilder.reflectionEquals(...)HashCodeBuilder.reflectionHashCode(...).过去让我感到很头疼 - 虽然当然如果你只是想对ID做"等于"它可能不适合你的情况.

我同意你应该@Override在覆盖equals(或任何其他方法)时使用注释.

  • 如果你是一个eclipse用户,你也可以去右键 - > source - >生成hashCode()和equals()`, (4认同)

bor*_*jab 5

另一个节省样板代码的快速解决方案是Lombok EqualsAndHashCode 注释。它简单、优雅且可定制。并且不依赖于IDE。例如;

import lombok.EqualsAndHashCode;

@EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{

    private long        errorNumber;
    private int         numberOfParameters;
    private Level       loggingLevel;
    private String      messageCode;
Run Code Online (Sandbox Code Playgroud)

请参阅可用于自定义在 equals 中使用哪些字段的选项。Lombok 在Maven中可用。只需将其添加到提供的范围即可:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)