Dictionary 为什么如果实现了hashCode方法,那么对于数据类型中的键,还必须实现equals方法?
数据类型:字典键Dictionary 为什么如果实现了hashCode方法,那么对于数据类型中的键,还必须实现equals方法?,dictionary,Dictionary,数据类型:字典键 有人能告诉我同时实现两者(hashCode/equals)的重要性吗。因为我认为如果我们实现hashCode方法equals,我们将比较hashCodes并给出等式 仅仅因为散列码相等并不意味着底层对象相等。可能的哈希代码数量有限,因此必然会发生冲突。您应该实现一个健壮的.Equals(),以便您可以实际测试相等性。哈希代码不能保证唯一性。例如,在大多数语言中,哈希代码采用2^32个值。如果您有一个4整数的类,那么该类可能有多少唯一的状态/实例?(2^32)^4. 这意味着即使
有人能告诉我同时实现两者(hashCode/equals)的重要性吗。因为我认为如果我们实现hashCode方法equals,我们将比较hashCodes并给出等式 仅仅因为散列码相等并不意味着底层对象相等。可能的哈希代码数量有限,因此必然会发生冲突。您应该实现一个健壮的
.Equals()
,以便您可以实际测试相等性。哈希代码不能保证唯一性。例如,在大多数语言中,哈希代码采用2^32个值。如果您有一个4整数的类,那么该类可能有多少唯一的状态/实例?(2^32)^4. 这意味着即使实现了一个完美的哈希代码,仍然会有2^(32*3)个冲突,其中一对不同的对象具有相同的哈希代码
因此,HashCode被用作第一个“快速”比较,以查找与您正在查找的对象相似的对象。一旦你进入一组对象,就会检查每个对象是否相等,看看是否有一个对象正是你想要的。问题是,仅仅因为两个对象具有相同的哈希代码并不意味着它们相等 只有2^32个可能的哈希代码(32位整数)。仔细想想,你会发现可能的字符串数量要大得多。因此,并非每个字符串都有唯一的哈希代码 而且,许多类的
GetHashCode
方法实现得很差
例如,下面是.Net源代码中的Point.GetHashCode
:
public override int GetHashCode() {
return x ^ y;
}
请注意,
(2,3)
将具有与(3,2)
相同的hashcode,即使它们不相等。尽管有一些没有表现出这种行为,但根据定义,它们仍然不是唯一的。IMHO,实现hashcode和equals的原因如下:
哈希表允许基于键快速访问元素。这是可能的,因为它的实施
哈希表内部使用bucket存储其值。将每个桶看作一个数组。
还有一系列这样的桶。因此它变成了一个二维数组。键的hashcode是一种机制,通过该机制,哈希表可以直接跳转到存储值的bucket的索引
例如:
下面我为一个类编写了代码,我将使用该类作为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")));
}
}
因此(“a,“java”)的键、值对将存储为第7个bucket中的第一个元素
当您执行hashMap.put(newkey(“k”),“python”);
桶索引再次计算为
indexofBucket=key.hashCode()%numberofbucket//7,其中key=“k”
这是同一个桶,第七个指数的桶
现在,当您通过键检索值时
hashMap.get(new Key("a"));
哈希表将计算出索引,因此:
indexOfBucket = key.hashCode() % numberOfBuckets //7
此时,哈希表将在bucket中找到两个元素。现在,它必须返回的元素将由(在一个简单的实现中,我猜)迭代每个元素并比较键的相等值来决定。如果没有相等值,哈希表甚至可能无法找到您添加到其中的元素
要查看此操作,请注释掉Key类的equals实现并运行代码
null
null
打印为输出,而使用equals实现后,您将看到
"java",
"python"
长期受伤的解释,但希望有帮助,但我们根据数据类型中的值生成hashCode,因此我们为不同的成员值生成不同的hashCode,为相同的成员值生成相同的hashCode(?)具有相同成员值的两个对象将生成相同的哈希代码,但这并不意味着它们是相同的对象。实现Equals是为了确保两个对象引用指向相同的对象,而不仅仅是具有相同属性值的对象。
"java",
"python"