Java .equals() instanceof 子类?为什么不调用超类 equals 而不是使其成为 final?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18575294/
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
Java .equals() instanceof subclass? Why not call superclass equals instead of making it final?
提问by user2622016
It is stated in Object's .equals(Object)
javadoc:
它在 Object 的.equals(Object)
javadoc 中说明:
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
Almost everywhere in example code I see overridden .equals(Object)
method which uses instanceof
as one of the first tests, for example here: What issues / pitfalls must be considered when overriding equals and hashCode?
在示例代码中几乎无处不在,我看到被覆盖的.equals(Object)
方法instanceof
用作第一个测试之一,例如在这里:覆盖 equals 和 hashCode 时必须考虑哪些问题/陷阱?
public class Person {
private String name;
private int age;
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
...
}
}
}
Now with class SpecialPerson extends Person
having in equals
:
现在,随着class SpecialPerson extends Person
具有equals
:
if (!(obj instanceof SpecialPerson))
return false;
we con not guarantee that .equals()
is symmetric.
It has been discussed for example here: any-reason-to-prefer-getclass-over-instanceof-when-generating-equals
我们不保证它.equals()
是对称的。例如这里已经讨论过:any-reason-to-prefer-getclass-over-instanceof-when-generating-equals
Person a = new Person(), b = new SpecialPerson();
a.equals(b); //sometimes true, since b instanceof Person
b.equals(a); //always false
Maybe I should add in the beginning of SpecialPerson's equals direct call to super?
也许我应该在 SpecialPerson 的开头添加对 super 的直接调用?
public boolean equals(Object obj) {
if( !obj instanceof SpecialPerson )
return super.equals(obj);
...
/* more equality tests here */
}
采纳答案by Aaron Digulla
A lot of the examples use instanceof
for two reasons: a) it folds the null check and type check into one or b) the example is for Hibernate or some other code-rewriting framework.
许多示例instanceof
出于两个原因使用:a) 它将空检查和类型检查合并为一个或 b) 该示例用于 Hibernate 或其他一些代码重写框架。
The "correct" (as per the JavaDoc) solution is to use this.getClass() == obj.getClass()
. This works for Java because classes are singletons and the VM guarantees this. If you're paranoid, you can use this.getClass().equals(obj.getClass())
but the two are really equivalent.
“正确”(根据 JavaDoc)解决方案是使用this.getClass() == obj.getClass()
. 这适用于 Java,因为类是单例的,VM 保证了这一点。如果你是偏执狂,你可以使用,this.getClass().equals(obj.getClass())
但两者实际上是等价的。
This works most of the time. But sometimes, Java frameworks need to do "clever" things with the byte code. This usually means they create a subtype automatically. Since the subtype should be considered equal to the original type, equals()
must be implemented in the "wrong" way but this doesn't matter since at runtime, the subtypes will all follow certain patterns. For example, they will do additional stuff before a setter is being called. This has no effect on the "equalness".
这在大多数情况下都有效。但有时,Java 框架需要用字节码做“聪明”的事情。这通常意味着它们会自动创建子类型。由于子类型应被视为与原始类型相同,因此equals()
必须以“错误”的方式实现,但这并不重要,因为在运行时,子类型都将遵循某些模式。例如,他们会在调用 setter 之前做一些额外的事情。这对“平等”没有影响。
As you noticed, things start to get ugly when you have both cases: You really extend the base types and you mix that with automatic subtype generation. If you do that, you must make sure that you never use non-leaf types.
正如您所注意到的,当您同时拥有这两种情况时,事情就会变得很糟糕:您确实扩展了基本类型,并将其与自动子类型生成混合在一起。如果你这样做,你必须确保你永远不会使用非叶类型。
回答by JB Nizet
Your attempt at solving the problem is not correct. Suppose you have 2 subclasss SpecialPerson
and BizarrePerson
. With this implementation, BizarrePerson
instances could be equal to SpecialPerson
instances. You generally don't want that.
您解决问题的尝试不正确。假设您有 2 个子类SpecialPerson
和BizarrePerson
. 通过这种实现,BizarrePerson
实例可以等于SpecialPerson
实例。你通常不希望那样。
回答by dharam
You are missing something here. I will try to highlight this:
你在这里遗漏了一些东西。我将尝试强调这一点:
Suppose you have Person person = new Person()
and Person personSpecial = new SpecialPerson()
then I am sure you would not like these two objects to be equal. So, its really working as required, the equal must return false.
假设您有Person person = new Person()
,Person personSpecial = new SpecialPerson()
然后我确定您不希望这两个对象相等。因此,它确实按要求工作,equal 必须返回 false。
Moreover, symmetry specifies that the equals()
method in both the classes must obey it at the same time. If one equals return true and other return false, then I would say the flaw is in the equals overriding.
此外,对称性指定equals()
两个类中的方法必须同时遵守它。如果一个等于返回 true 而另一个返回 false,那么我会说缺陷在于 equals 覆盖。
回答by Philipp Sander
don't use instanceof
. use this.getClass() == obj.getClass()
instead. then you are checking for this exact class.
不要使用instanceof
. 使用this.getClass() == obj.getClass()
来代替。那么你正在检查这个确切的类。
when working with equals
you should always use the hashCode
and override that too!
与equals
您合作时,您也应该始终使用hashCode
并覆盖它!
the hashCode method for Person could look like this:
Person 的 hashCode 方法可能如下所示:
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
and use it like this in your equals method:
并在您的 equals 方法中像这样使用它:
if (this.hashCode() != obj.hashCode())
{
return false;
}
回答by supercat
A type should not consider itself equal to an object of any other type--even a subtype--unless both objects derive from a common class whose contract specifies how descendants of different types should check for equality.
一个类型不应该认为自己等于任何其他类型的对象——甚至是子类型——除非两个对象都派生自一个公共类,该类的契约指定了不同类型的后代应该如何检查相等性。
For example, an abstract class StringyThing
could encapsulate strings, and provide methods to do things like convert to a string or extract substrings, but not impose any requirements on the backing format. One possible subtype of StringyThing
, for example, might contain an array of StringyThing
and encapsulate the value of the concatenation of all those strings. Two instances of StringyThing
would be defined as equal if conversion to strings would yield identical results, and comparison between two otherwise-indistinguishable StringyThing
instances whose types knew nothing about each other may have to fall back on that, but StringyThing
-derived types could include code to optimize various cases. For example, if one StringyThing
represents "M
repetitions of character ch
" and another represents "N
repetitions of the string St", and the latter type knows about the first, it could check whether St
contains nothing but M/N
repetitions of the character ch
. Such a check would indicate whether or not the strings are equal, without having to "expand out" either one of them.
例如,抽象类StringyThing
可以封装字符串,并提供执行转换为字符串或提取子字符串等操作的方法,但不对支持格式强加任何要求。StringyThing
例如, 的一种可能子类型可能包含一个数组StringyThing
并封装所有这些字符串的串联值。StringyThing
如果转换为字符串会产生相同的结果,则两个 的实例将被定义为相等,并且在StringyThing
类型彼此一无所知的两个其他无法区分的实例之间进行比较可能不得不依赖于这一点,但是 -StringyThing
派生类型可以包含优化各种案件。例如,如果一个StringyThing
代表“M
重复字符ch
”,另一个代表“N
字符串 St" 的重复,而后一种类型知道第一种,它可以检查是否只St
包含M/N
字符的重复ch
。这样的检查将指示字符串是否相等,而不必“展开”任何一个其中。