我不明白为什么Map.put()只检查hashcode()和Map.containsKey()只检查equals()。
为什么不保持一致性。在两种情况下都检查哈希码或在两种情况下均等。
答案 0 :(得分:3)
两个或多个对象可以返回相同的hashCode
,但如果它们是equals
,则它们只能相同。
Map#containsKey
只解释了实现应使用equals
方法来比较密钥。但这并不意味着实现无法使用hashCode
来搜索可能所需键的键。这在HashMap#containsKey
实施中已经注明。从Java 8的来源发布该方法的实现:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
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;
}
请注意TreeMap
不能与hashCode
一起使用,而是使用键的自然比较。因此,在此实现中无需使用hashCode
。请注意,TreeMap#containsKey
更改了javadoc以解释它没有使用equals
方法。从Java 8的源代码中显示此方法的源代码,它根本不使用equals
(评论是我的):
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
//navigating through the nodes of the inner red black tree
while (p != null) {
//using result of compareTo method to check if the key is found
//this replaces usage of equals method
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
答案 1 :(得分:2)
这是因为hashCode()
和equals()
之间的关系。如果两个对象相等,则它们必须具有相同的哈希码,但反向不一定是真的。
因此,如果您想查看某个集合是否包含某些内容,那么不能使用hashCode()
进行相等性检查,否则如果您碰巧有两个不相等的对象返回相同的数字hashCode()
,你开始遇到重大问题。
此外,由于哈希表的工作方式,hashCode()
更适用于补充 equals()
,主要用于哈希集合。来自Object
的javadoc:
public int hashCode()
返回对象的哈希码值。支持此方法是为了哈希表的优势,例如HashMap提供的哈希表。
哈希表通过计算对象的“哈希”来工作,在一些数学运算之后,它为后备数组提供索引。鉴于良好的hashCode()
实现,这允许使用摊销的O(1)put()
,get()
,contains()
和其他方法进行收集,这是非常理想的属性。
然而,这主要是一个便利功能。最后,地图必须仍然使用equals()
,以确保您检索的对象实际上是您想要的对象。事实上,可以编写完全不使用Map
的{{1}}实现,例如使用hashCode()
的{{1}}。
答案 2 :(得分:0)
我得到了答案。
我们不能对add()使用contains(),因为当我们想要找到存储元素的位置/地址时,我们使用hashcode()并插入它。但是,在检查密钥是否已存在时,使用contains(),必须使用equals方法将现有元素与样本密钥进行比较。
现在我明白了。谢谢大家。