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