java在给定另一个等价键对象的情况下获取映射项的当前键
假设我有一个HashMap<K, V>
和两个类型为K
的对象,它们彼此相等,但不是同一个对象,并且映射有一个键k1
的条目
给定k2
,我是否可以仅使用HashMap
(无外部数据结构)中以恒定时间执行的方法(即O(1)时间复杂度)获取对k1
的引用
代码:
K k1, k2;
k1.equals(k2) // true
k1.hashCode() == k2.hashCode() // true
k1 == k2 // false
myMap.put(k1, someValue);
K existingKey = getExistingKey(myMap, k2);
existingKey == k1 // true <- this is the goal
<K> K getExistingKey(HashMap<K, V> map, K k) {
// What impl goes here?
}
我希望使用Java8添加的各种方法之一,例如compute()
来“嗅探”lambda中的现有密钥,但是它们都(似乎)将新密钥对象传递给lambda,而不是现有密钥
遍历entrySet()
将找到现有的键,但不是在固定时间内
我可以使用Map<K, K>
来存储密钥,并保持同步,但这并不能回答问题
# 1 楼答案
你在找这样的东西
起初,我认为创建一个自定义的
HashMap
子类来返回它是很容易的,因为get(K key)
只是其中
Node
实现Map.Entry
。这看起来像:不幸的是,
getNode()
和hash()
都是包私有的,因此对子类不可见下一步是将类放入
java.util
,但在Java 9中,这失败了我觉得你在这里运气不好
<>我实际上认为一个^ {< CD8>}方法对API是有用的补充,您可以考虑提交一个增强请求。# 2 楼答案
我不知道您在内存使用方面有多受限,但是如果您可以使用} 方法:
LinkedHashMap
而不是HashMap
(LinkedHashMap
使用额外的引用来保持插入顺序),那么您可以利用它的^{我认为代码是不言自明的。我们保留了对原始密钥的引用,这是从
removeEldestEntry
方法的参数中获取的。 至于removeEldestEntry
方法的返回值,它是false
,因此我们不允许删除最老的条目(毕竟,我们不希望映射充当缓存)现在,使用公共插入顺序
LinkedHashMap
,由put
和putAll
(来自removeEldestEntry
方法文档)自动调用removeEldestEntry
方法:因此,我们现在需要做的就是实现
getExistingKey
方法,使其在不修改映射的情况下调用put
,您可以如下所示:这是因为,当映射已经包含映射到给定键的条目时,
put
方法会在不触碰键的情况下替换该值我不确定我做的空检查,也许你需要改进。当然,这个
HackedMap
不支持并发访问,但是HashMap
和LinkedHashMap
也不支持您可以安全地使用
HackedMap
而不是HashMap
。这是测试代码:下面是我使用的
Key
类: