获取给定另一个等效密钥对象的地图条目的当前密钥
假设我有一个HashMap<K, V>
和类型K
的两个对象彼此相等但不是相同的对象,并且该地图具有密钥的条目。获取给定另一个等效密钥对象的地图条目的当前密钥
鉴于k2
,可以使用仅在HashMap
(无外部数据结构)中执行的方法(即O(1)时间复杂度)获得对的引用吗?
在代码:
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?
}
我希望使用与Java 8中添加的各种方法中的一种,如compute()
“嗅”在现有的拉姆达内的关键,但他们都(似乎)将新的密钥对象传递给lambda,而不是现有密钥。
通过entrySet()
的迭代可以找到现有密钥,但不是在固定时间内。
我可以使用Map<K, K>
来存储密钥,我可以保持它的同步,但这并不回答这个问题。
回答:
您正在寻找的东西像
Map.Entry<K,V> getEntry(K key)
起初我以为它会很容易使HashMap
自定义子类,返回这一点,因为get(K key)
只是
public V get(Object key) { Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
其中Node
工具Map.Entry
。这看起来像:
public class MyHashMap<K,V> extends HashMap<K,V> {
public MyHashMap() {}
// Other constructors as needed
public Map.Entry<K, V> getEntry(K key)
{
Map.Entry<K, V> e = getNode(hash(key),key);
return e;
}
}
不幸的是,getNode()
和hash()
都是包私有,因此不可见的子类。
下一步是把类java.util
但这未能在Java中9
The package java.util conflicts with a package accessible from another module: java.base
我觉得你的运气了这里。
我实际上认为一个getEntry()
方法将是API的一个有用的补充,你可以考虑提交一个增强请求。
回答:
我不知道如何限制你对于内存的使用,但如果你能使用LinkedHashMap
代替HashMap
(LinkedHashMap
使用额外的引用,以保持插入顺序),那么你可以利用它的removeEldestEntry
方法:
public class HackedMap<K, V> extends LinkedHashMap<K, V> { K lastKey;
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
lastKey = eldest.getKey();
return false;
}
K getLastKey() {
return lastKey;
}
}
我认为这个代码是不言自明的。我们保留对原始密钥的参考,我们从removeEldestEntry
方法的论点中获取。 至于removeEldestEntry
方法的返回值,它是false
,所以我们不允许删除最老的条目(毕竟,我们不希望该映射工作为缓存)。
现在,具有共同的插入顺序LinkedHashMap
,所述removeEldestEntry
方法被自动通过put
和putAll
称为(从removeEldestEntry
方法文档):
此方法由PUT和的putAll插入一个新的条目之后调用进入地图。
因此,所有我们现在需要做的就是实现你getExistingKey
方法以这样一种方式,它调用put
不修改地图,你可以做如下:
<K, V> K getExistingKey(HackedMap<K, V> map, K k) { if (k == null) return null;
V v = map.get(k);
if (v == null) return null;
map.put(k, v);
return map.getLastKey();
}
这样做是因为,当映射已包含映射到给定键的条目时,put
方法将替换该值而不触摸键。
我不知道我做过的空检查,也许你需要改进。当然这HackedMap
不支持并发访问,但HashMap
和LinkedHashMap
也不支持。
您可以放心地使用HackedMap
而不是HashMap
。这是测试代码:
Key k1 = new Key(10, "KEY 1"); Key k2 = new Key(10, "KEY 2");
Key k3 = new Key(10, "KEY 3");
HackedMap<Key, String> myMap = new HackedMap<>();
System.out.println(k1.equals(k2)); // true
System.out.println(k1.equals(k3)); // true
System.out.println(k2.equals(k3)); // true
System.out.println(k1.hashCode() == k2.hashCode()); // true
System.out.println(k1.hashCode() == k3.hashCode()); // true
System.out.println(k2.hashCode() == k3.hashCode()); // true
System.out.println(k1 == k2); // false
System.out.println(k1 == k3); // false
System.out.println(k2 == k3); // false
myMap.put(k1, "k1 value");
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k1 value}
myMap.put(k3, "k3 value"); // Key k1 (the one with its field d='KEY 1') remains in
// the map but value is now 'k3 value' instead of 'k1 value'
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k3 value}
Key existingKey = getExistingKey(myMap, k2);
System.out.println(existingKey == k1); // true
System.out.println(existingKey == k2); // false
System.out.println(existingKey == k3); // false
// Just to be sure
System.out.println(myMap); // {Key{k=10, d='KEY 1'}=k3 value}
这里的Key
类我用:
public class Key { private final int k;
private final String d;
Key(int k, String d) {
this.k = k;
this.d = d;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key1 = (Key) o;
return k == key1.k;
}
@Override
public int hashCode() {
return Objects.hash(k);
}
@Override
public String toString() {
return "Key{" +
"k=" + k +
", d='" + d + '\'' +
'}';
}
}
以上是 获取给定另一个等效密钥对象的地图条目的当前密钥 的全部内容, 来源链接: utcz.com/qa/260922.html