Object
在 Java 中有hashCode
方法,但是,它仅用于关联容器,如HashSet
or HashMap
。为什么会这样设计?Hashable
具有hashCode
方法的接口看起来更加优雅的解决方案。
2 回答
在我看来,主要论点是hashCode
可以为任何 Java 对象计算一个定义良好的默认值,以及一个同样定义良好的equals
. 根本没有充分的理由对所有对象保留此功能,当然也有很多理由不保留它。所以这在我的书中是显而易见的。
这个问题被声称与另一个问题重复,它询问为什么没有接口的行为类似于Comparator
(与 不同Comparable
)但用于散列。.NET 包含这样一个接口,称为IEqualityComparer
,看起来 Java 也可以。事实上,如果有人想拥有一个 Java 集合,例如以不区分大小写的方式将字符串映射到其他对象(可能是 最常见的用法IEqualityComparer
),则必须将字符串包装在对象中,其hashCode
和equals
方法在不区分大小写的基础上起作用.
我怀疑最大的问题是,虽然“equalityComparer”接口可能很方便,但在许多情况下,有效地测试等价关系需要缓存信息。例如,虽然不区分大小写的字符串散列函数可以制作传入字符串的仅大写副本并调用hashCode
它,但很难避免对特定字符串的哈希码的每个请求都重复转换为大写和该大写值的散列。相比之下,“不区分大小写的字符串”对象可以包含字符串的仅大写副本的字段,然后只需为实例生成一次。
如果 AnEqualityComparer
包含类似 a 将原始字符串转换为仅大写字符串的功能,则可以实现合理的性能WeakHashMap<string,string>
,但是这样的设计要么需要不同的线程使用不同EqualityComparer
的实例,尽管缺乏外部可见状态,否则需要性能抢夺锁定和即使在单线程场景中也可以同步代码。
顺便说一句,比较器样式接口出现的第二个问题是,使用外部提供的比较器的集合类型(无论是比较等级还是相等)是比较器本身成为使用它的类的状态的一部分。如果哈希表使用不同的 EqualityComparer 实例,则可能无法知道它们是否可以安全地被视为等效,即使两个比较器在所有情况下的行为都相同。