覆盖java equals()方法的quirk

问题

今天我遇到了一个有趣的(也是非常令人沮丧的)问题,这导致了我认为经过严格测试的类崩溃并导致我花了很长时间才能找到的错误。

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

无论如何 -

我正在开发一个基本的购物车,其中可能包含一个ArrayListofBook对象。为了实现Cart的addBook(),removeBook()和231632017方法,我想检查Book是否已经存在于Cart中。我走了 -

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

一切都在测试中运行良好。我创建了6个对象并用数据填充它们。在Cart上做了很多添加,删除,has()操作,一切正常。我读到你的cane要么equals(TYPE var)equals(Object o) { (CAST) var }但是我认为既然它正在工作,那就无所谓了。

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

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);
}

突然间,equals(Book b)方法不再有效。这花了很长时间没有一个好的调试器跟踪,并假设Cartclass已正确测试和正确。将equals()方法交换到以下内容后:

public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}

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


#1 热门回答(310 赞)

在Java中,继承自Objectequals()方法是:

public boolean equals(Object other);

换句话说,参数必须是typeObject

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...
}

使用@Override注释可以帮助实现愚蠢的错误。

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


#2 热门回答(99 赞)

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

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


#3 热门回答(11 赞)

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

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

我同意你应该在覆盖equals(或任何其他方法)时使用@Overrideanannot。