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

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

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

无论如何-

我正在开发一个基本的购物车,可以包含一个 ABC1对象的 ArrayList。为了实现购物车的 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;
}

测试中一切正常。我创建了6个对象并用数据填充它们。在 Cart上执行许多添加、删除、()操作,所有操作都能正常工作。我读到你可以 要么有 ABC1或 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);
}

突然之间,equals(Book b)方法不再有效。如果没有一个好的调试器,并且假设 Cart类被正确测试和正确,那么要花费很长的时间来跟踪。在将 equals()方法交换到以下方法之后:

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

一切又开始运转了。方法决定不采用 Book 参数是否有原因,即使它显然是 曾经是一个 Book对象?唯一的区别似乎是它是从同一个类中实例化的,并且只用一个数据成员填充。我非常非常困惑。拜托,说点什么吧?

257515 次浏览

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

public boolean equals(Object other);

换句话说,参数必须是 Object类型。这称为 重写; 您的方法 public boolean equals(Book other)equals()方法执行称为 超载的操作。

ArrayList使用重载的 equals()方法来比较内容(例如,对于它的 contains()equals()方法)和 没有重载的方法。在您的大多数代码中,调用没有正确覆盖 Object的等式的代码是可以的,但是与 ArrayList不兼容。

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

我每次重写等于以下值:

@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注释可以帮助大量愚蠢的错误。

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

你的问题有点跑题了,但还是值得一提:

Commons Lang 提供了一些优秀的方法,可以用来重写 equals 和 hashcode。看看 反射等于(...)映射 HashCode (...)。在过去省去了我很多麻烦——当然,如果你只是想在 ID 上做“等于”,这可能不适合你的情况。

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

如果您使用 Eclipse,只需到顶部菜单

Source —— > Generate equals () and HashCode ()

另一个节省样板代码的快速解决方案是 龙目岛等式和哈希码注释。它简单、优雅和可定制

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;

请参阅可用的 选择来自定义在等号中使用哪些字段。龙目岛可在 ABc1下载。只需将其添加到 提供范围:

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

instanceOf语句通常用于实现 equals。

这是一个常见的陷阱!

问题在于,使用 instanceOf违反了对称性原则:

(object1.equals(object2) == true) 如果,也只有如果 (object2.equals(object1))

如果第一个等于为 true,并且 object2是 那么第二个等于的值将返回 false!

如果 ob1所属的被视为的类被声明为 final,则此 问题不会出现,但一般而言,你应按以下方法进行测试:

如果不是 this.getClass() != otherObject.getClass();,返回 false,否则测试 为了平等而比较的字段!

在安卓工作室是 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();
}

Record Id 是对象的属性

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