我很好奇,在Java集合库中, HashMap 有一个方法可以搜索名为 containsValue的特定对象值的存在性(对象值) 撤回 布尔 ,但 值对象 strong>通过 值对象 ,直接通过 get(对象键)方法提供键。现在,我知道 HashMap 的目的是通过键访问对象值,但在特殊情况下可能需要通过对象值进行检索,那么为什么没有 getValue(对象值)方法?我问这个,因为方法 containsValue() 实现搜索 对象值 的算法更快比我的自定义搜索(见下面)。另外,有没有更好的方法在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;
}
}
答案 0 :(得分:0)
hashMap.values().contains(findCust)
根据您的"业务规则"您将需要在客户上使用equals和hashCode。 (例如,两个客户具有相同的" id"但是具有不同的其他值"等于" ???? ...显然你已经这样做,因为你使用的是equals。 ..)
答案 1 :(得分:0)
集合框架的基本假设是,如果两个对象是.equals
,则它们在各方面都是可互换的。鉴于这种假设,没有理由从Map
中获取值,因为您已经拥有equals
且可互换的值。就集合框架而言,这两种方法是完全等效的:
for (V value : map.values()) {
if (value.equals(myValue)) {
return value;
}
}
和
if (map.containsValue(myValue)) {
return myValue;
}
这个假设在许多地方内置于集合框架中,这是许多例子中的一个。
答案 2 :(得分:0)
HashMap旨在使用您用于将某些值放入地图的键的hashcode()
和equals()
来帮助进行常量查找。
如果你看一下HashMap的内部结构,它只不过是一个数组。每个索引称为一个桶,可以通过规范化当前数组的长度和传递的密钥的哈希码来获得。找到存储桶后,它会将元素存储在该特定索引处。但是如果已经存在一些元素存储在该索引中,它们将形成这些元素的LinkedList,链接具有相同hashcode()
但不同equals()
条件的所有值。
在Java 8中,如果该链表中的元素数量达到某个阈值(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()
返回一个Collection,其迭代器实现为遍历HashMap中的每个元素,在每次迭代中提供对Value
对象的访问。
containsValue()
用于你想要做的事情,如果地图中已有某些值,但你不需要那个值来继续你的流程。这只是一种方便的方法,因为如果你是使用values
,您将创建一个Collection对象和一个迭代器对象来迭代它们,但使用containsValue()
,您只需要两个嵌套的for循环。我认为没有getValue()
的原因是为了鼓励HashMap的目的 - 使用hashcode&amp;和接近恒定的时间查找。等于一些关键。
values()
。这与在循环中调用map.get(key)
不同,因为您不必标准化哈希码,找到存储桶,然后在每次迭代中找到链表中的元素,只需循环自然顺序,顺便说一下元素在数组中布局。
如果您执行此值查找的次数太多,则会失去HashMap提供的常量查找的优势。如果您只是浏览搜索某些值的值,我建议您使用ArrayList
。如果该列表中的元素太多,并且您需要经常搜索某个随机值,请对列表进行排序并使用二进制搜索。