重写java equals()方法-不工作?

重写java equals()方法-不工作?,java,equals,overriding,Java,Equals,Overriding,今天,我在equals()方法中遇到了一个有趣(而且非常令人沮丧)的问题,它导致了我认为是一个经过良好测试的类崩溃,并导致了一个花了我很长时间才发现的bug 为了完整起见,我没有使用IDE或调试器,只是使用了老式的文本编辑器和System.out。时间非常有限,这是一个学校项目 无论如何- 我正在开发一个基本的购物车,它可以包含一个ArrayList的Book对象。为了实现购物车的addBook()、removeBook()和hasBook()方法,我想检查Book是否已经存在于购物车中。所以我

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

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

无论如何-

我正在开发一个基本的购物车,它可以包含一个
ArrayList
Book
对象。为了实现购物车的
addBook()
removeBook()
hasBook()
方法,我想检查
Book
是否已经存在于
购物车中。所以我走了-

public boolean equals(Book b) {
    ... // More code here - null checks
    if (b.getID() == this.getID()) return true;
    else return false;
}
在测试中一切都很好。我创建了6个对象并用数据填充它们。在
购物车上执行许多添加、删除和has()操作,一切正常。我读到你可以有
equals(typevar)
或者
equals(objecto){(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);
}
public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}
突然间,
equals(b书)
方法不再有效。如果没有一个好的调试器,并且假设
Cart
类经过了正确的测试,那么跟踪它需要很长时间。将
equals()
方法应用于以下对象后:

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);
}
public boolean equals(Object o) {
    Book b = (Book) o;
    ... // The rest goes here   
}
一切又开始起作用了。方法决定不接受Book参数,即使它显然是
Book
对象,这有什么原因吗?唯一的区别似乎是它是从同一个类中实例化的,并且只填充了一个数据成员。我非常非常困惑。请解释一下?

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

public boolean equals(Object other);
换句话说,参数的类型必须是
Object
。这被称为覆盖;您的方法
public boolean equals(Book other)
equals()方法执行所谓的重载

ArrayList
使用重写的
equals()
方法来比较内容(例如,对于其
contains()
equals()
方法),而不是重载的方法。在大多数代码中,调用没有正确覆盖
对象
的equals的函数是可以的,但与
数组列表
不兼容

因此,不正确重写该方法可能会导致问题

每次I override等于以下值:

@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
注释有助于避免许多愚蠢的错误


只要您认为您正在重写一个超类或接口的方法,就可以使用它。那样的话,如果你用错误的方法,你会得到一个编译错误。

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

有一些很好的方法可以用来重写equals和hashcode。退房并离开。过去帮我省去了很多头疼的事——当然,如果你只是想在身份证上做到“平等”,那可能不适合你的情况


我还同意,无论何时重写equals(或任何其他方法),都应该使用
@Override
注释。

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

源-->生成等于()和 hashCode()


另一个节省样板代码的快速解决方案是。它简单、优雅且可定制。而且不依赖于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;
请参阅可自定义要在equals中使用的字段。龙目山在这里随处可见。只需将其添加到提供的范围中:


org.projectlombok
龙目
1.14.8
假如

在equals的实现中经常使用
instanceOf
语句

这是一个常见的陷阱

问题是使用
instanceOf
违反了对称规则:

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

如果第一个等于true,并且object2是 obj1所属的类,则第二个等号将返回false

如果ob1所属的类被声明为final,那么 问题不会出现,但一般来说,您应该进行以下测试:

this.getClass()!=getClass()如果不是,则返回false,否则返回test
要比较的字段是否相等

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

例如:

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

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;
    }
考虑:

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

我知道我违反了关于通过反射重写equals方法的“约定”-但是我需要一种快速的方法来检查ArrayList中是否存在对象,而不使用泛型。这是学习Java和equals的一个很好的课程这是支持@Override注释的一个很好的论点。。。如果OP使用@Override,他的编译器会告诉他,他实际上并没有重写父类方法……他从来没有意识到@Override,谢谢!我还想补充一点,重写hashCode()确实应该已经完成,并且可能会更快地发现错误。一些IDE(例如Eclipse)甚至可以根据类成员变量为您自动生成equals()和hashCode()方法。
if(!(MyClass的其他实例))返回falseMyClass
扩展了另一个类,则code>返回
false
。但是如果另一个类扩展了MyClass,则不会返回false。
equal
不应该少一些矛盾吗?当使用上一个空检查的实例时是多余的。如果您是eclipse用户,您也可以