在生成 .equals() 时,有什么理由更喜欢 getClass() 而不是 instanceof?
我正在使用 Eclipse 生成 .equals()
和 .hashCode()
,并且有一个选项标记为“使用 'instanceof' 来比较类型”。 默认情况下不选中此选项并使用 .getClass()
来比较类型。 有什么理由让我更喜欢 .getClass()
而不是 instanceof
?
不使用instanceof
:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
使用instanceof
:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
我一般都会勾选instanceof
选项,然后进去去掉“if (obj = = null)
”检查。 (这是多余的,因为 null 对象总是会失败 instanceof
。)有什么理由认为这是一个坏主意吗?
I'm using Eclipse to generate .equals()
and .hashCode()
, and there is an option labeled "Use 'instanceof' to compare types". The default is for this option to be unchecked and use .getClass()
to compare types. Is there any reason I should prefer .getClass()
over instanceof
?
Without using instanceof
:
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Using instanceof
:
if (obj == null)
return false;
if (!(obj instanceof MyClass))
return false;
I usually check the instanceof
option, and then go in and remove the "if (obj == null)
" check. (It is redundant since null objects will always fail instanceof
.) Is there any reason that's a bad idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
Josh Bloch 赞成你的方法:
另请参阅这个答案。
《Effective Java》第 3 章 也涵盖了这一点。
Josh Bloch favors your approach:
See also this SO answer.
Effective Java chapter 3 also covers this.
如果您使用
instanceof
,使您的equals
实现final
将保留该方法的对称契约:x.equals(y) = = y.等于(x)。 如果
final
看起来有限制性,请仔细检查您的对象等效概念,以确保您的重写实现完全维护由Object
类建立的契约。我在这里想要表达的是,如果您认为 getClass() 是保持对称性的唯一可靠方法,那么您可能会以错误的方式使用 equals() 。
当然,使用 getClass() 来保留 equals() 所需的对称性很容易,但这只是因为 x.equals(y) 和
y.equals(x)
始终为 false。 里氏可替换性会鼓励您找到一种保持对称性的实现,在有意义时可以产生true
。 如果一个子类具有完全不同的平等概念,那么它真的是一个子类吗?If you use
instanceof
, making yourequals
implementationfinal
will preserve the symmetry contract of the method:x.equals(y) == y.equals(x)
. Iffinal
seems restrictive, carefully examine your notion of object equivalence to make sure that your overriding implementations fully maintain the contract established by theObject
class.What I'm trying to get at here is that if you believe
getClass()
is the only reliable way to preserve symmetry, you are probably usingequals()
the wrong way.Sure, it's easy to use
getClass()
to preserve the symmetry required ofequals()
, but only becausex.equals(y)
andy.equals(x)
are always false. Liskov substitutability would encourage you to find a symmetry-preserving implementation that can yieldtrue
when it makes sense. If a subclass has a radically different notion of equality, is it really a subclass?Angelika Langers 平等的秘密 深入探讨对一些常见且众所周知的例子(包括 Josh Bloch 和 Barbara Liskov)进行了长时间而详细的讨论,发现了大多数例子中的一些问题。 她还深入了解了
instanceof
与getClass
。 其中的一些引述Angelika Langers Secrets of equals gets into that with a long and detailed discussion for a few common and well-known examples, including by Josh Bloch and Barbara Liskov, discovering a couple of problems in most of them. She also gets into the
instanceof
vsgetClass
. Some quote from it使用
getClass
的原因是为了确保equals
合约的对称性。 来自 equals 的 JavaDocs:通过使用instanceof,有可能不对称。 考虑这个例子:
狗延伸了动物。
Animal 的
equals
对 Animal 进行instanceof
检查。Dog 的
equals
对 Dog 进行instanceof
检查。给 Animal a 和 Dog d (其他字段相同):
这违反了对称性。
为了严格遵循 equal 契约,必须保证对称性,因此类需要相同。
The reason to use
getClass
is to ensure the symmetric property of theequals
contract. From equals' JavaDocs:By using instanceof, it's possible to not be symmetric. Consider the example:
Dog extends Animal.
Animal's
equals
does aninstanceof
check of Animal.Dog's
equals
does aninstanceof
check of Dog.Give Animal a and Dog d (with other fields the same):
This violates the symmetric property.
To strictly follow equal's contract, symmetry must be ensured, and thus the class needs to be the same.
这是一场宗教辩论。 这两种方法都有其问题。
布洛赫在Effective Java 第二版:
This is something of a religious debate. Both approaches have their problems.
Bloch has another relevant piece of advice in Effective Java Second Edition:
如果我错了,请纠正我,但是当您想确保您的实例不是您要比较的类的子类时, getClass() 会很有用。 如果您在这种情况下使用instanceof,您将无法知道这一点,因为:
Correct me if I am wrong, but getClass() will be useful when you want to make sure your instance is NOT a subclass of the class you are comparing with. If you use instanceof in that situation you can NOT know that because:
如果您想确保仅该类匹配,请使用 getClass() == 。 如果你想匹配子类,那么需要
instanceof
。另外,instanceof 不会与 null 匹配,但与 null 进行比较是安全的。 所以你不必对它进行空检查。
If you want to ensure only that class will match then use
getClass() ==
. If you want to match subclasses theninstanceof
is needed.Also, instanceof will not match against a null but is safe to compare against a null. So you don't have to null check it.
这取决于您是否考虑给定类的子类是否等于其父类。
在这里我会使用“instanceof”,因为我想要将 LastName 与 FamilyName 进行比较,
在这里我会使用“getClass”,因为该类已经表明这两个实例不相等。
It depends if you consider if a subclass of a given class is equals to its parent.
here I would use 'instanceof', because I want a LastName to be compared to FamilyName
here I would use 'getClass', because the class already says that the two instances are not equivalent.
instanceof 适用于同一类或其子类的实例
ArryaList 和 RoleList 都是 instanceof 列表
而
getClass() == o.getClass() 仅当两个对象( this 和 o )属于完全相同的类时才为 true。
因此,根据您需要比较的内容,您可以使用其中之一。
如果您的逻辑是:“只有当一个对象属于同一类时,它们才等于其他对象”,您应该选择“等于”,我认为这是大多数情况。
instanceof works for instences of the same class or its subclasses
ArryaList and RoleList are both instanceof List
While
getClass() == o.getClass() will be true only if both objects ( this and o ) belongs to exactly the same class.
So depending on what you need to compare you could use one or the other.
If your logic is: "One objects is equals to other only if they are both the same class" you should go for the "equals", which I think is most of the cases.
这两种方法都有其问题。
如果子类改变了身份,那么你需要比较它们的实际类。 否则,就会违反对称性。 例如,不同类型的
Person
不应被视为等效,即使它们具有相同的名称。但是,某些子类不会更改标识,并且这些子类需要使用
instanceof
。 例如,如果我们有一堆不可变的Shape
对象,那么长度和宽度为 1 的Rectangle
应该等于单位Square
。在实践中,我认为前一种情况更有可能成立。 通常,子类化是你身份的基本组成部分,并且与你的父母一模一样,除非你能做一件小事,但这并不意味着你就是平等的。
Both methods have their problems.
If the subclass changes the identity, then you need to compare their actual classes. Otherwise, you violate the symmetric property. For instance, different types of
Person
s should not be considered equivalent, even if they have the same name.However, some subclasses don't change identity and these need to use
instanceof
. For instance, if we have a bunch of immutableShape
objects, then aRectangle
with length and width of 1 should be equal to the unitSquare
.In practice, I think the former case is more likely to be true. Usually, subclassing is a fundamental part of your identity and being exactly like your parent except you can do one little thing does not make you equal.
实际上,instanceof 检查对象是否属于某个层次结构。 例如:Car 对象属于 Vehical 类。 因此“Vehical 的 new Car() 实例”返回 true。 而“new Car().getClass().equals(Vehical.class)”返回 false,虽然 Car 对象属于 Vehical 类,但它被归类为单独的类型。
Actually instanceof check where an object belongs to some hierarchy or not. ex: Car object belongs to Vehical class. So "new Car() instance of Vehical" returns true. And "new Car().getClass().equals(Vehical.class)" return false, though Car object belongs to Vehical class but it's categorized as a separate type.