HashMap 有 containsValue 方法,但没有 getValue 方法

HashMap has containsValue method, but not getValue method

我很好奇在 Java 集合库中,HashMap 有一个方法可以搜索特定 对象值 调用了 containsValue(Object value) 返回一个 boolean,但不存在通过值对象获取值对象的方法 直接像您一样通过 get(Object key) 方法提供 key 。现在,我知道 HashMap 的目的是通过键访问对象值,但在特殊情况下可能希望通过 对象值 检索,那么为什么没有 getValue(Object value) 方法呢?我问这个,因为方法 containsValue() 实现搜索 object 值的算法 比我的自定义搜索更快(见下文)。另外,在 Java 7 中使用 HashMap 是否有更好的方法来完成此搜索?

代码片段:

// Custom Search
MyCustomer findCust = new MyCustomer(50000, "Joe Bloggs", "London");
for (MyCustomer value : hashMap.values()) {

    if (value.equals(findCust)) { // found
            cust = value;
            break;
    }

}
hashMap.values().contains(findCust)

您将需要基于您的 "business rules" 的 Customer 上的 equals 和 hashCode(例如,是否有两个具有相同 "id" 但具有不同其他值 "equal" 的客户???? ...显然您已经在这样做了,因为您使用的是 equals...)

集合框架的基本假设是,如果两个对象是 .equals,则它们在任何方面都可以互换。鉴于该假设,没有理由从 Map 中获取值,因为您已经拥有一个 equals 且可互换的值。就Collections Framework而言,这两种方法是完全等价的:

for (V value : map.values()) {
  if (value.equals(myValue)) {
    return value;
  }
}

if (map.containsValue(myValue)) {
  return myValue;
}

这个假设在很多地方都内置在 Collections Framework 中,这只是众多示例之一。

HashMap 旨在使用 hashcode()equals() 用于将某些值放入映射中的键来帮助不断查找。

如果你看一下HashMap的内部结构,它就是一个数组。每个索引称为一个桶,可以通过规范化当前数组的长度和您传递的密钥的哈希码来获得。找到桶后,它会将元素存储在该特定索引处。但是,如果该索引中已经存储了一些元素,它们将形成这些元素的 LinkedList 链接所有具有相同 hashcode() 但不同 equals() 标准的值。

在Java8中,如果该链表中的元素数量达到某个阈值(8),则该链表甚至更改为TreeMap以提高性能。

关于您的问题,containsValue() 基本上遍历数组中的所有存储桶,并再次遍历每个存储桶的链表中的所有元素

// iterate through buckets
for (int i = 0; i < table.length; ++i) {

      // iterate through each element in linked list at each bucket
      for (Node<K,V> e = table[i]; e != null; e = e.next) {
              if ((v = e.value) == value ||
                      (value != null && value.equals(v)))
                   return true;
      }
 }

HashMap.values() returns 一个带有迭代器的集合,用于遍历 HashMap 中的每个元素,在每次迭代中提供对 Value 对象的访问。

containsValue() 当你想做某事时如果某些值已经存在于地图中但你不需要该值来继续你的 flow.This 只是一种方便的方法,因为如果您使用 values,您将创建一个集合对象和一个迭代器对象来迭代它们,但使用 containsValue(),您只有两个嵌套的 for 循环。我认为没有 getValue() 的原因是为了鼓励 HashMap 的目的——使用哈希码和某个键的等值进行近乎恒定的时间查找。

values() 当您基本上需要遍历所有值时使用。这与在循环中调用 map.get(key) 不同,因为您不必在每次迭代中对哈希码进行归一化,找到桶,然后在链表中查找元素,您只需按自然顺序循环即可,方式元素排列在数组中。

如果您多次执行此值查找方式,您将失去 HashMap 提供的持续查找的优势。如果您只想浏览搜索某个值的值,我建议您使用 ArrayList。如果该列表中的元素太多,并且您需要经常搜索一些随机值,请对列表进行排序并使用二分查找。