覆盖 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
Overriding the java equals() method - not working?
提问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 ArrayList
of Book
objects. In order to implement the addBook()
, removeBook()
, and hasBook()
methods of the Cart, I wanted to check if the Book
already existed in the Cart
. So off I go -
我开发一个基本的购物车可能包含ArrayList
的Book
对象。为了贯彻落实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 Cart
and 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 Book
object with onlythe ID
in 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 Cart
class 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 Book
object? 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 Object
is:
在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 ArrayList
uses 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 @Override
annotation 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 @Override
annotation 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 instanceOf
statement is often used in implementation of equals.
该instanceOf
语句常用于实现 equals。
This is a popular pitfall !
这是一个流行的陷阱!
The problem is that using instanceOf
violates 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...