在生成 .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) ”勾选。 (这是多余的,因为空对象总是会失败 instanceof 。)有什么理由是个坏主意吗?

原文由 Kip 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 599
2 个回答

如果您使用 instanceof ,则使您的 equals 实现 final 将保留方法的对称合约: x.equals(y) == y.equals(x) 如果 final 似乎具有限制性,请仔细检查您的对象等效概念,以确保您的覆盖实现完全维护由 Object 类建立的合同。


我想在这里说明的是,如果您认为 getClass() 是保持对称性的唯一可靠方法,那么您可能使用的是 equals() 错误的方法。

Sure, it’s easy to use getClass() to preserve the symmetry required of equals() , but only because x.equals(y) and y.equals(x) are always false. Liskov 可替换性将鼓励您找到一个保持对称的实现,它可以在有意义的时候产生 true 。如果一个子类有一个完全不同的平等概念,它真的是一个子类吗?

原文由 erickson 发布,翻译遵循 CC BY-SA 4.0 许可协议

Josh Bloch 赞成你的方法:

我喜欢 instanceof 方法的原因是当你使用 getClass 方法时,你有一个限制,即对象只等于同一类的其他对象,相同的运行时间类型。如果你扩展一个类并向它添加几个无害的方法,然后检查子类的某个对象是否等于超类的对象,即使这些对象在所有重要方面都相等,你也会得到令人惊讶的答案是它们不相等。事实上,这违反了对 Liskov 替换原则 的严格解释,并可能导致非常令人惊讶的行为。在 Java 中,它特别重要,因为大多数集合( HashTable 等)都基于 equals 方法。如果你把超类的一个成员作为键放在哈希表中,然后使用子类实例查找它,你将找不到它,因为它们不相等。

另请参阅 此 SO 答案

Effective Java 第 3 章 也介绍了这一点。

原文由 Michael Myers 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题