为什么不允许外部接口为哈希映射提供哈希码/等于?

2022-09-03 18:06:11

使用 a,提供自定义是微不足道的,因此覆盖了添加到映射中的对象提供的语义。然而,不能以这种方式控制;提供哈希值和相等性检查的函数不能“旁加载”。TreeMapComparatorComparableHashMap

我怀疑设计一个界面并将其改装成(或一个新类)既简单又有用?像这样的东西,除了更好的名称:HashMap

  interface Hasharator<T> {
    int alternativeHashCode(T t);
    boolean alternativeEquals(T t1, T t2);
  }

  class HasharatorMap<K, V> {
    HasharatorMap(Hasharator<? super K> hasharator) { ... }
  }

  class HasharatorSet<T> {
    HasharatorSet(Hasharator<? super T> hasharator) { ... }
  }

区分大小写的 Map 问题得到了一个微不足道的解决方案:

 new HasharatorMap(String.CASE_INSENSITIVE_EQUALITY);

这是否可行,或者您能看到这种方法的任何根本问题吗?

该方法是否在任何现有的(非 JRE)库中使用?(试过谷歌,没有运气。

编辑:hazzen提出的不错的解决方法,但我担心这是我试图避免的解决方法...... ;)

编辑:更改标题不再提及“比较器”;我怀疑这有点令人困惑。

编辑:与性能相关的可接受答案;希望得到更具体的答案!

编辑:有一个实现;请参阅下面的可接受答案。

编辑:改写了第一句话,以更清楚地表明这是我所追求的旁加载(而不是排序;排序不属于HashMap)。


答案 1

.NET通过IEqualityComparer(对于可以比较两个对象的类型)和IEquatable(对于可以将自身与另一个实例进行比较的类型)来实现这一点。

事实上,我认为在java.lang.Object或System.Object中定义相等和哈希码是完全错误的。特别是平等,很难以一种对继承有意义的方式来定义。我一直想写博客关于这个...

但是,是的,基本上这个想法是合理的。


答案 2

对你来说有点晚了,但对于未来的访问者来说,可能值得知道commons-collections有一个(在3.2.2中,在4.0中使用泛型)。您可以重写这些受保护的方法以实现所需的行为:AbstractHashedMap

protected int hash(Object key) { ... }
protected boolean isEqualKey(Object key1, Object key2) { ... }
protected boolean isEqualValue(Object value1, Object value2) { ... }
protected HashEntry createEntry(
    HashEntry next, int hashCode, Object key, Object value) { ... }

这种替代方案的一个示例实现是commons-collections自己的(只有3.2.2,因为Java自1.4以来有自己的)。HashedMapIdentityMap

这不如为实例提供外部“”强大。您必须为每个哈希策略实现一个新的映射类(组合与继承回击...)。但知道这一点仍然很好。HasharatorMap