在 Java(并发)HashMap 中搜索 *the* 键

Searching for *the* key in a Java (Concurrent)HashMap

我可以通过搜索 equals() 中的键来获取对(并发)HashMap(或 HashSet)中实际键的引用吗?怎么样?

我正在寻找类似 getEntry(K key).getKey() 的东西,每次我在第一次插入后访问密钥时都会给我相同的引用,因此我可以使用此引用而不是新生成的密钥来节省内存.

(显然可以为此目的专门使用一个特殊的 HashMap,但实际上我已经有了一个映射,想知道我是否可以为此目的使用它的键)

您似乎是在说您想要引用作为映射中的键保存的对象,使用另一个对象找到,该对象恰好符合 Object::equals 合同。

虽然我还没有尝试过这段代码,但我认为你可以通过获取地图键的 Set 来做到这一点。然后转换为List。在该列表中找到您想要的对象,从列表的元素中检索引用。

Map< Car , Integer > map = … ;
Car car = new Car( … ) ;
map.put( car , 42 ) ;

Set< Car > carSet = map.keySet() ;
List< Car > carList = List.copyOf( carSet ) ;
Car similarCar = … ;
int index = carList.indexOf( similarCar ) ;
Car originalCar = carList.get( index ) ;  

boolean same = ( car == originalCar ) ;

您还可以从一组键创建一个流,搜索一个匹配项,同时让流在第一个匹配项停止。

想获得密钥的“原始”是相当奇怪的......通常,用新创建的密钥进行轮询是“便宜的”,并且它们可以在以后被垃圾收集。我猜你有一个相当奇特的用例。

也就是说,开箱即用的 HashMap 无法实现您想要的效果。您最接近的做法是扩展它以公开 getNode(...) 方法,从而允许您访问密钥。

您无法从 HashMap 中检索原始密钥,除非像这样进行暴力顺序搜索:

K keyToLookup = ...;

K originalKey = map.keySet().stream().filter(keyToLookup::equals).findAny().orElse(null);

选项 1:在值中嵌入密钥

HashMap 的解决方法当然是将键对象作为值的一部分:

  • 实际上将键对象作为值对象的一部分,这通常是固有的,例如用户名到用户对象的映射。可能需要修改值对象,并且可能需要在更新以引用不同的值对象时删除并重新添加映射条目。

  • 单独Map<K, K>。效率较低,因为您必须查找两次。

  • 通过将值更改为 key/value 对,例如Map<K, Entry<K, V>>。这可能是最好的解决方案,但确实需要注意确保 Entry 的键对象始终是原始键。


选项 2:使用 NavigableMap

如果 Map 可以从 HashMap 更改为 NavigableMap, e.g. a TreeMap, it supports retrieving the original key object from the map, e.g. using the ceilingEntry(K key)​ 方法。

关键对象必须实现 Comparable or the TreeMap can use a custom Comparator。无论哪种情况,实现都必须 与 equals.

一致

并非所有键类型都可以定义相对顺序,因此可能无法使用 NavigableMap

K keyToLookup = ...;

Entry<K,​V> entry = map.ceilingEntry​(keyToLookup);
if (entry != null && entry.getKey().equals(keyToLookup)) {
    K originalKey = entry.getKey();
    V value = entry.getValue();
    // code here
} else {
    // key not found
}