3 回答
TA贡献2039条经验 获得超7个赞
Josh Bloch喜欢你的方法:
我赞成这种
instanceof
方法的原因是,当你使用这种getClass
方法时,你有一个限制,即对象只等于同一个类的其他对象,相同的运行时类型。如果扩展一个类并为它添加几个无害的方法,那么检查一下子类的某个对象是否等于超类的对象,即使对象在所有重要方面都相同,你也会得到令人惊讶的答案是他们并不平等。事实上,这违反了对利斯科夫替代原则的严格解释,并且可能导致非常令人惊讶的行为。在Java中,它特别重要,因为大多数集合(HashTable
等等)基于equals方法。如果您将超类的成员作为键放在哈希表中,然后使用子类实例查找它,您将找不到它,因为它们不相等。
另见这个SO答案。
有效的Java 第3章也涵盖了这一点。
TA贡献1804条经验 获得超2个赞
Angelika Langers 平等的秘密通过对一些常见和众所周知的例子进行了长时间的详细讨论,其中包括Josh Bloch和Barbara Liskov,他们发现了大多数问题。她还进入了instanceof
VS getClass
。有人引用它
结论
解剖了四个任意选择的equals()实现的例子,我们得出什么结论?
首先:在equals()的实现中,有两种截然不同的方式来执行类型匹配检查。类可以通过instanceof运算符允许超类和子类对象之间的混合类型比较,或者类可以通过getClass()测试将不同类型的对象视为不相等。上面的示例很好地说明了使用getClass()的equals()实现通常比使用instanceof的实现更强大。
instanceof测试仅对最终类是正确的,或者至少方法equals()在超类中是最终的。后者基本上意味着没有子类必须扩展超类的状态,但只能添加与对象的状态和行为无关的功能或字段,例如瞬态或静态字段。
另一方面,使用getClass()测试的实现始终符合equals()契约; 他们是正确和强大的。但是,它们在语义上与使用instanceof测试的实现非常不同。使用getClass()的实现不允许比较子类和超类对象,即使子类没有添加任何字段,甚至不想重写equals()。这样一个“普通的”类扩展例如是在为这个“普通”目的而定义的子类中添加调试打印方法。如果超类通过getClass()检查禁止混合类型比较,那么普通扩展将无法与其超类相比。这是否完全取决于类的语义和扩展的目的。
添加回答
举报