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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/185937/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 11:03:30  来源:igfitidea点击:

Overriding the java equals() method - not working?

javaequalsoverriding

提问by Josh Smeaton

I ran into an interesting (and very frustrating) issue with the equals()method today which caused what I thought to be a well tested class to crash and cause a bug that took me a very long time to track down.

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

Just for completeness, I wasn't using an IDE or debugger - just good old fashioned text editor and System.out's. Time was very limited and it was a school project.

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

Anyhow -

总之——

I was developing a basic shopping cart which could contain an ArrayListof Bookobjects. In order to implement the addBook(), removeBook(), and hasBook()methods of the Cart, I wanted to check if the Bookalready existed in the Cart. So off I go -

我开发一个基本的购物车可能包含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;
}

All works fine in testing. I create 6 objects and fill them with data. Do many adds, removes, has() operations on the Cartand everything works fine. I read that you can either have equals(TYPE var)or equals(Object o) { (CAST) var }but assumed that since it was working, it didn't matter too much.

在测试中一切正常。我创建了 6 个对象并用数据填充它们。在 上执行许多添加、删除、has() 操作Cart,一切正常。我读到您可以拥有equals(TYPE var)equals(Object o) { (CAST) var }假设,因为它正在工作,所以没有太大关系。

Then I ran into a problem - I needed to create a Bookobject with onlythe IDin it from within the Book class. No other data would be entered into it. Basically the following:

然后,我遇到了一个问题-我需要创建一个Book与对象ID从Book类内它。不会在其中输入其他数据。基本上如下:

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

All of a sudden, the equals(Book b)method no longer works. This took a VERY long time to track down without a good debugger and assuming the Cartclass was properly tested and correct. After swaapping the equals()method to the following:

突然之间,该equals(Book b)方法不再有效。如果没有良好的调试器并假设Cart该类经过正确测试和正确,这需要很长时间才能进行跟踪。将equals()方法交换为以下内容后:

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

Everything began to work again. Is there a reason the method decided not to take the Book parameter even though it clearly was a Bookobject? The only difference seemed to be it was instantiated from within the same class, and only filled with one data member. I'm very very confused. Please, shed some light?

一切又开始工作了。该方法是否有理由决定不采用 Book 参数,即使它显然一个Book对象?唯一的区别似乎是它是从同一个类中实例化的,并且只填充了一个数据成员。我非常非常困惑。拜托,照亮一些?

采纳答案by jjnguy

In Java, the equals()method that is inherited from Objectis:

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

public boolean equals(Object other);

In other words, the parameter must be of type Object. This is called overriding; your method public boolean equals(Book other)does what is called overloadingto the equals()method.

换句话说,参数的类型必须是Object。这称为覆盖;你的方法public boolean equals(Book other)做什么叫做重载equals()方法。

The ArrayListuses overridden equals()methods to compare contents (e.g. for its contains()and equals()methods), notoverloaded ones. In most of your code, calling the one that didn't properly override Object's equals was fine, but not compatible with ArrayList.

ArrayList重写应用equals()方法来比较的内容(例如,用于其contains()equals()方法),超载的。在您的大部分代码中,调用没有正确覆盖Object的 equals 的代码很好,但与ArrayList.

So, not overriding the method correctly can cause problems.

因此,不正确覆盖该方法可能会导致问题。

I override equals the following everytime:

我每次都覆盖等于以下内容:

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

The use of the @Overrideannotation can help a ton with silly mistakes.

@Override注释的使用可以帮助解决很多愚蠢的错误。

Use it whenever you think you are overriding a super class' or interface's method. That way, if you do it the wrong way, you will get a compile error.

每当您认为要覆盖超类或接口的方法时,请使用它。这样,如果您以错误的方式执行此操作,则会出现编译错误。

回答by jjnguy

Slightly off-topic to your question, but it's probably worth mentioning anyway:

您的问题有点偏离主题,但无论如何可能值得一提:

Commons Langhas got some excellent methods you can use in overriding equals and hashcode. Check out EqualsBuilder.reflectionEquals(...)and HashCodeBuilder.reflectionHashCode(...). Saved me plenty of headache in the past - although of course if you just want to do "equals" on ID it may not fit your circumstances.

Commons Lang有一些很好的方法,你可以使用它们来覆盖 equals 和 hashcode。查看EqualsBuilder.reflectionEquals(...)HashCodeBuilder.reflectionHashCode(...)。过去让我很头疼——当然,如果你只是想在 ID 上做“等于”,它可能不适合你的情况。

I also agree that you should use the @Overrideannotation whenever you're overriding equals (or any other method).

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

回答by Fred

If you use eclipse just go to the top menu

如果您使用 eclipse 只需转到顶部菜单

Source --> Generate equals() and hashCode()

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

回答by borjab

Another fast solution that saves boilerplate code is Lombok EqualsAndHashCode annotation. It is easy, elegant and customizable. And does not depends on the IDE. For example;

另一个节省样板代码的快速解决方案是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;

See the optionsavaliable to customize which fields to use in the equals. Lombok is avalaible in maven. Just add it with providedscope:

查看可用于自定义在 equals 中使用哪些字段的选项。Lombok 在maven可用。只需使用提供的范围添加它:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.14.8</version>
    <scope>provided</scope>
</dependency>

回答by Nikel8000

the instanceOfstatement is often used in implementation of equals.

instanceOf语句常用于实现 equals。

This is a popular pitfall !

这是一个流行的陷阱!

The problem is that using instanceOfviolates the rule of symmetry:

问题是 usinginstanceOf违反了对称规则:

(object1.equals(object2) == true)if and only if(object2.equals(object1))

(object1.equals(object2) == true)当且仅当(object2.equals(object1))

if the first equals is true, and object2 is an instance of a subclass of the class where obj1 belongs to, then the second equals will return false!

如果第一个 equals 为真,并且 object2 是 obj1 所属类的子类的实例,那么第二个 equals 将返回 false!

if the regarded class where ob1 belongs to is declared as final, then this problem can not arise, but in general, you should test as follows:

如果ob1所属的被关注类被声明为final,则不会出现这个问题,但一般情况下,应该进行如下测试:

this.getClass() != otherObject.getClass();if not, return false, otherwise test the fields to compare for equality!

this.getClass() != otherObject.getClass();如果不是,则返回 false,否则测试字段以比较是否相等!

回答by David Hackro

in Android Studio is alt + insert ---> equals and hashCode

在 Android Studio 中是 alt + insert ---> equals 和 hashCode

Example:

例子:

    @Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Proveedor proveedor = (Proveedor) o;

    return getId() == proveedor.getId();

}

@Override
public int hashCode() {
    return getId();
}

回答by vootla561

recordId is property of the object

recordId 是对象的属性

@Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Nai_record other = (Nai_record) obj;
        if (recordId == null) {
            if (other.recordId != null)
                return false;
        } else if (!recordId.equals(other.recordId))
            return false;
        return true;
    }

回答by bcsb1001

Consider:

考虑:

Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...