Java:需要一个哈希映射表,其中提供一个函数来进行哈希处理。

18
我想了解一个类似于常规HashMap/Hashtable的地图,但它需要接受一个返回哈希码并执行相等性测试函数,而不是让HashMap使用Object.hashCode/equals。
我不能使用TreeMap,因为对象没有实现Comparable,也没有稳定的处理不相等对象的方法。 我们不能使用System.identityHashCode,因为有可能存在不相等对象的冲突。
理想情况下,如果地图能够像我们可以向TreeMap提供自定义比较器一样,接受一个函数,那将是非常好的,而不是让TreeMap将参数强制转换为Comparable。
唯一的解决办法是包装每个键并使包装器进行自定义哈希/等于操作,但肯定有更好的方法。

1
由于存在不相等对象的潜在冲突,因此无法使用System.identityHashCode。 这基本上是哈希表的一部分。 每个哈希表实现都会发生哈希冲突。 - biziclop
这些对象都是同一类型吗?它们实现Comparable会有什么障碍吗?我想可以通过子类化HashMap并覆盖函数并将函数引用传递给它们来设置解决方案...但这似乎比实现Comparable需要更多的努力。 - roberttdev
这是一个多用途的 q,很多时候不幸的是类不属于你,你不能改变它们,因此需要提供一个自定义函数来处理哈希/相等性测试。 - mP.
@biziclop,当然哈希冲突会发生,但我希望该函数也能处理相等性测试,这样我的函数可以决定在计算哈希和相等性时什么更重要。 - mP.
只是想让你知道,我有完全相同的问题。我目前正在使用一个带有自己的equals()和hashCode()方法的包装器对象,而这些包装器占用了数百兆字节的堆内存。我计划采用HashMap的开源实现并进行调整。 - Michael Kay
5个回答

10

你是否考虑过在需要缓存的对象周围包装一个简单的包装器?

class Wrapper {
   YourObject object;

   public boolean equals(Object someOther) {
   ...
   }
   public int hashCode() {
   }
}

1
他在原帖中说过(你可能需要重新阅读一下),但我同意这很可能是最好的解决方案,不应该被那么快地抛弃。 - Hovercraft Full Of Eels
2
你可以更进一步地采取这个解决方案,编写一个简单的 Map 包装器,使用此散列包装器作为内部实现。该 Map 包装器可以处理添加或检索对象时的包装和解包装。 - jt.
@jt 的问题是还需要处理 keySet、entrySet 和它们的迭代器等,这并不难,但确实需要一些工作... - mP.
问题在于需要额外的内存和性能来构建新实例。每次从映射中检索值时,都会进行实例构建。您不能仅使用equals来比较未包装的键,因为您不知道您的包装映射如何处理比较-它是否始终将包含的键与查询的键进行比较,还是也会反向比较它们。 - SpaceTrucker

2
Plume-lib的WeakHasherMap可以满足您的需求:它的构造函数以Hasher对象作为参数,该对象定义了hashCode()方法和equals()方法。

(这在你提出问题时就已存在,但我现在才注意到你的问题,距你提问已有6.5年之久。)

编辑:我是plume-lib的维护者。


确实,这是一个救命的答案,应该是今天解决这个问题的答案。 - Panayotis

1
正如其他答案所建议的那样,将您的对象包装在具有所需hashCode和equals的对象中通常是最好的选择。如果在罕见情况下,您希望函数使用Object上的原始equals和hashCode实现,那么确实有IdentityHashMap可用于此用例。但是,我欣赏您想要的功能可能不仅仅如此。

0
使用TreeMap时,地图中的对象不需要实现Comparable。

你误解了如果我使用TreeMap会发生的问题。如果我提供自己的自定义比较器,那么如何比较不相等的对象?我不能使用System.identityHashcode,因为当不相等的对象发生哈希码冲突时会出现另一个问题! - mP.
您需要实现 Comparator 的 compare() 方法,以便根据键类的可用公共方法和/或字段来一致地排序键。 - Harv
或者只需将哈希码作为整数进行比较 :). 很遗憾没有IEqualityComparer<T>。 - Hans

-1

我之前提出了一个“哈希函数”的接口。

现在你需要拿到任何一个哈希表的实现(例如OpenJDK是GPL),并将所有对hashCode().equals()的调用修改为对这个哈希对象的调用。我曾经做过这件事(很多年前),但没有公开发布。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接