没有人真正谈论equals()和hasCode()的这一方面,但对equals()和hashCode()行为可能产生巨大影响。在处理引用其他对象的更复杂的对象时非常重要。
Joshua Bloch 在他的 Effective Java 中甚至没有在他的“覆盖 equals() 方法”一章中提到它。他所有的例子都是像 Point 和 ColorPoint 这样的琐事,都只有原始或接近原始的类型。
可以避免递归吗?有时几乎没有。认为:
Person {
String name;
Address address;
}
这两个字段都必须转到业务键(正如 Hibernate 的人所说的那样),它们都是值组件(正如 Joshua Bloch 所拥有的那样)。Address 本身就是一个复杂的对象。递归。
请注意,Eclipse 和 IntelliJ 等 IDE 确实会生成递归 equals() 和 hashCode()。默认情况下,它们使用所有字段。如果你大量使用生成器工具,你就会自找麻烦。
一个麻烦是你会得到一个StackOverflowError。这是我的简单测试证明它。
所需要的只是将另一个对象作为“值组件”的类,形成一个对象图和推荐的 equals() 实现。是的,您需要在那个循环中绘制图表,但这并非不切实际(想象分子、地图上的路径、相互关联的交易......)。
另一个麻烦是性能。equals() 推荐的实际上是比较两个对象图,可能是巨大的图,最终可能会在不知情的情况下比较数千个节点。并不是所有的都在内存中是必需的!考虑到某些对象可能是可延迟加载的。一个 equals() 或 hashCode() 调用最终可能会加载一半的数据库。
悖论是,你越严格地重写 equals() 和 hashCode() 就像你被鼓励做的那样,你就越有可能遇到麻烦。