提问者:小点点

Java-如何通过键获取存储在HashMap中的键对象(或条目)?


我想为可用于查询地图的每个键获取“规范”键对象。看这里:

Map<UUID, String> map = new HashMap();
UUID a = new UUID("ABC...");
map.put(a, "Tu nejde o zamykání.");

UUID b = new UUID("ABC...");
String string = map.get(b); // This gives that string.

// This is what I am looking for:
UUID againA = map.getEntry(b).key();
boolean thisIsTrue = a == againA;

HashMap使用的是相同的多个唯一对象。所以我想从地图中获取实际的密钥,无论使用哪个对象来查询地图,它都将始终是相同的。

有没有办法从地图中获取实际的关键对象?我在界面上看不到任何东西,但可能是我忽略了一些聪明的技巧?

(迭代所有条目或键不算数。)


共3个答案

匿名用户

有没有办法从地图中获取实际的关键对象?

好的,我要对你的意思做一些假设。毕竟,你说过你的问题不需要澄清,所以我能看到的明显含义一定是正确的。对吗?:-)

答案是否定的,没有办法。

示例场景(不可编译!)

UUID uuid = UUID.fromString("xxxx-yyy-zzz");
UUID uuid2 = UUID.fromString("xxxx-yyy-zzz");  // same string
println(uuid == uuid2);  // prints false
println(uuid.equals(true));  // prints true

Map<UUID, String> map = new ...
map.put(uuid, "fred");
println(map.get(uuid)); // prints fred
println(map.get(uuid2)); // prints fred (because uuid.equals(uuid2) is true)

... 但是,除了迭代键集或条目集之外,API没有提供在映射中查找实际键的方法(在上面的示例中,它是uuid)。而且我还不知道有任何现有的映射类(标准或第三方)提供这种映射。

但是,您可以使用一个用于返回实际键对象的附加方法来实现自己的映射类。没有技术上的原因可以解释为什么您不能,尽管您将有更多的代码要编写、测试、维护等等。

但我要补充一点,我同意吉姆·加里森的观点。如果您有一个场景,其中有UUID对象(具有值相等语义),并且还希望实现标识相等语义,那么您的应用程序的设计可能有问题。正确的方法是更改UUID。fromString(…)实现始终为相同的输入字符串返回相同的UUID对象。

这并不是说这种映射实现不存在。但如果是这样的话,如果你仔细看的话,你应该能够找到它。请注意,要求我们查找或推荐图书馆的问题是离题的

匿名用户

有一种(相对)简单的方法可以做到这一点。我不时在需要时在我的应用程序中这样做...不是为了==测试,而是为了在存在数万个对象时减少存储的相同对象的数量,并相互交叉引用。这大大减少了我的内存使用,提高了性能...同时仍然使用equals()进行相等性测试。

只需维护一个用于插入密钥的平行映射。

Map<UUID, UUID> interned_keys = ...

UUID key = ...
if (interned_keys.contains(key))
    key = interned_keys.get(key)

当然,当被存储的对象知道自己的身份时,情况要好得多。然后你基本上可以免费得到实习机会。

class Item {
    UUID key;
    // ...
}

Map<UUID, Item> map = ...
map.put(item.key, item);

UUID key = ...
key = map.get(key).key;  // get interned key

匿名用户

我认为有充分的理由需要实际的密钥。例如,为了节省内存。还要记住,实际关键点可能存储其他对象。例如,假设您有一个图的顶点。顶点可以存储实际数据(例如字符串)以及关联顶点。顶点哈希值只能依赖于数据。因此,要查找包含一些数据D的顶点,请查找包含数据D和无关联值的顶点。现在,如果可以返回贴图中的实际顶点,则可以获得顶点的实际关联。

在我看来,许多map实现都可以轻松地提供getEntry方法。例如,get的HashMap实现是:

  public V get(Object key) {
    Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
  }

  final Node<K,V> getNode(int hash, Object key) {
    Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
            ((k = first.key) == key || (key != null && key.equals(k))))
            return first;
        if ((e = first.next) != null) {
            if (first instanceof TreeNode)
                return ((TreeNode<K,V>)first).getTreeNode(hash, key);
            do {
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    return null;
 }

可以使用getNode方法返回条目:

 public getEntry(Object key){
   Node<K,V> e = getNode(hash(key),key);
   if(e == null) return null;
   return new Entry<>(e.key,e.value);
 }