首先,我不要求他们之间的区别。
我有一个想法,我想更多的大脑来验证,这似乎能够(大多数)采用这两种方法的优点。
简而言之,Java中的equals()
通常看起来像这样。
public boolean equals(Object other) {
if (other == null) return false;
if (this == other) return true;
if (this and other is not of the same type) return false
// then actual equals checking
}
问题出在" 这个和其他类型不同的"检查。
有一群人更喜欢使用if (! (other instanceof MyClass))
,其缺点是
MyClass
的子类并且已被覆盖equals()
,则a.equals(b)
和b.equals(a)
将不相同equals()
,声明最终其他人喜欢使用if (getClass() != other.getClass())
,但缺点是
MyClass
的子类应该可以代替MyClass
使用。a.equals(b)
属于a
而MyClass
属于b
的子类,则MyClass
将为false,即使内部属性只是相同。我有一个想法,我希望人们验证。
这种方法应该
equals()
,则结果应该仍然是对称的子类仍然可以用作其父类型(在equals()
方面,当然不会覆盖equals
)
public class Parent {
@Override
public boolean equals(Object other) {
if (other == null) return false;
if (this == other) return true;
if (!(other instanceof Parent)) return false;
try {
if (other.getClass().getMethod("equals", Object.class).getDeclaringClass() != Parent.class) {
return other.equals(this);
}
} catch(Exception neverHappen){}
// do actual checking
}
}
主要的想法是,如果this
遇到Parent
个对象,但该对象的equals()
未在Parent
中声明(即该对象是子类,重写equals()
,我将equals
调用委托给子类对象(或者可能只返回false)。
使用这种方法是否有任何我忽略的缺点? (我想性能损失将是一个问题,但我相信getClass().method("equals").getDeclaringClass()
的呼叫应该相当便宜?)
答案 0 :(得分:1)
如评论中所述,如果子类确实super.equals(..)
,您将获得堆栈溢出。为了防止这种情况,你最终会重写每个孩子的整个父母equals(..)
,这甚至是最糟糕的设计。
不知何故,它取决于您首先实现继承的方式/原因。孩子应该与父母相提并论吗?比较法有意义吗? (已编辑)
如果覆盖等于,则根据定义,您不会尊重LSP。
如果一个孩子有更多的参数(这意味着它覆盖了equals方法),那么它不应该等于它的父级,这就是为什么我们可以在父级中使用getClass() != other.getClass()
进行比较。如果你想在你的孩子中使用父类equals()
(所以你不必重写所有内容),你就不会以堆栈溢出的方式结束; equals()
只会是假的,因为它们并不是平等的。
如果孩子与其父母相当怎么办?如果您尊重LSP,那么孩子不应该有与父母不同的equals()
(即:等于不应该被覆盖),我猜。所以不对称的情况不应该存在。
如果孩子与其父母相比,但有更多参数?现在这是您的设计,不尊重LSP,因此您可以自行查看它在您的上下文中的含义并采取相应的行动。
编辑:@Adrian yes," symmmetry是否有意义"措辞很差,我应该说"比较是否有意义?"。对于您的示例,如果您将两个子类与getClass()
进行比较,并且他们使用super也使用getClass()
,它将返回true(测试将是redondant,因为this.getClass()
和{{ 1}}将始终在子级和父级中具有相同的值。但正如我所说,如果你比较一个孩子和一个父母,它将是假的(如果他们有不同的参数,我认为这是正常的)。
为什么只在equals上使用final作为实例?你说的是,因为可能的不对称,而使用other.getClass()
不可能对继承进行不对称,所以在这种情况下使它成为最终是没有用的。
作为旁注,如果您使用getClass()
,那么同一父母的多个孩子将无法比较(始终返回false)。如果你使用getClass()
,他们可以,但如果他们这样做,没有孩子应该覆盖instanceof
,因为它有破坏对称性的风险。 (我想你有这个,但我想知道什么时候选择equals()
而不是insteanceof
,如果它有问题的话。)
答案 1 :(得分:0)
使用这种方法有什么缺点吗?
它不会起作用。调用方法在编译时确定。多态性仅适用于.
之前的引用而不是之后的引用。
other.equals(this); // always calls equals(Object); as `other` is an Object.
另外
other.getClass().getMethod("equals", /* method with no args */).getDeclaringClass();
我假设你想要other.getClass()。getMethod(" equals",Parent.class)但你必须抓住NoSuchMethodException
我相信调用getClass()。方法("等于")。getDeclaringClass()应该相当便宜?
不在我的选择中。它比从磁盘上读取内容更快,但你不会经常这么做。
最后但并非最不重要的是,你应该确保a.equals(b)==> b.equals(a)和a.equals(b)然后a.hashCode()== b.hashCode()很难做到a
和b
是不同的类型。