获取给定另一个等效密钥对象的地图条目的当前密钥

假设我有一个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代替HashMapLinkedHashMap使用额外的引用,以保持插入顺序),那么你可以利用它的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方法被自动通过putputAll称为(从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不支持并发访问,但HashMapLinkedHashMap也不支持。

您可以放心地使用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

回到顶部