数据类型:字典键
有人可以告诉我同时实现它们(hashCode / equals)的重要性。因为我认为如果我们实现hashCode方法equals将比较hashCodes并给我们相等。
答案 0 :(得分:5)
HashCode不保证唯一性。例如,HashCode在大多数语言中占用2 ^ 32个值。如果你有一个4个整数的类,你可以拥有多少个可能的独特状态/实例? (2 ^ 32)^ 4。这意味着即使你实现了一个完美的哈希码,你仍然会有2 ^(32 * 3)个冲突,其中一对不同的对象具有相同的哈希码。
因此,HashCode用作第一个“快速”比较,用于查找与您要查找的对象类似的对象。一旦你找到一组对象,就会检查每个对象的相等性,看看是否有一个正是你正在寻找的对象。
答案 1 :(得分:4)
仅仅因为哈希码相等并不意味着底层对象是相等的。可能的哈希码数量有限,因此必然存在冲突。您应该实现一个健壮的.Equals()
,以便您可以实际测试相等性。
答案 2 :(得分:3)
问题在于,仅仅因为两个对象具有相同的哈希码并不意味着它们是相同的。
只有2 ^ 32个可能的哈希码(32位整数)。如果你考虑一下,你会发现可能的字符串数量要大得多。因此,并非每个字符串都有唯一的哈希码。
此外,许多类的GetHashCode
方法实施得很差。
例如,这里是来自.Net源代码的Point.GetHashCode
:
public override int GetHashCode() {
return x ^ y;
}
请注意,(2, 3)
将具有与(3, 2)
相同的哈希码,即使它们不相等。虽然are implementations没有表现出这种行为,但根据定义,它们仍然不是唯一的。
答案 3 :(得分:0)
恕我直言,实现hashcode和equals的原因是:
哈希表允许基于密钥快速访问元素。这是可能的,因为它的实施。
哈希表在内部使用存储桶来存储其值。将每个桶视为一个数组。 并且有一系列这样的桶。因此它变成了二维阵列。密钥的哈希码是一种机制,通过该机制,哈希表可以直接跳转到存储该值的存储桶的索引。
例如:
下面我编写了一个Class的代码,我将用它作为HashMap实例的键。
package com.aneesh.hashtable;
import java.util.HashMap;
public class Key {
private String key;
public Key(String key){
this.key = key;
}
@Override
public int hashCode() {
return key.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
public static void main(String[] args) {
HashMap<Key, String> hashMap = new HashMap<Key, String>();
hashMap.put(new Key("a"), "java");
hashMap.put(new Key("k"), "Python");
System.out.println(hashMap.get(new Key("a")));
System.out.println(hashMap.get(new Key("k")));
}
}
Key类的hashCode实现只是返回String类型的实例变量'key'的hashCode。 “a”的哈希码= 97 “k”= 107 //的哈希码有一个原因让我选择这两个键很快就会显而易见。
当你做hashMap.put(new Key(“a”),“java”); 哈希表必须确定将密钥值放入哪个存储桶。该代码将是
int indexofBucket = key.hashCode() % numberOfBuckets //7, where key is "a"
因此,(“a”,“java”)的键值对将被存储为第7个桶中的第一个元素。
当你做hashMap.put(new Key(“k”),“python”); 桶索引再次计算为 indexofBucket = key.hashCode()%numberOfBuckets // 7,其中key =“k”
这是同一个桶,第7个索引处的桶。
现在,当您通过键
检索值时hashMap.get(new Key("a"));
哈希表会因此找出索引:
indexOfBucket = key.hashCode() % numberOfBuckets //7
此时哈希表会在桶中找到两个元素。现在哪个元素必须返回它将由(在一个简单的实现中我猜测)迭代每个元素并比较键的等于。如果没有等于,哈希表甚至可能无法找到您添加到其中的元素。
要查看此操作,请注释掉Key类的equals实现并运行代码。你会看到
null
null
作为输出打印,而实现等于,您将看到
的输出"java",
"python"
长期受伤的解释,但希望有所帮助