为了哈希表的好处,我们有两个方法hashcode和equals.Internally当我们在hastable中添加一个键值对时,它首先进入key的哈希码方法并检查它是否等于任何先前键的哈希码值。如果不是那么它只是在哈希表中添加键值对,但如果它是相等的,那么它进入equals方法,我们再次提供一些逻辑来检查对象是否相等。所以我的问题是我们正在做的工作在equals方法中,我们可以消除它并在hashcode方法中放入相同类型的逻辑,我们提供不同的hashcode(取决于我们在equals方法中放置的逻辑)。通过这种方式,我们可以仅使用哈希码mthod来管理哈希表,并且无需使用equals方法。
以Employee类为例,我们将id,salary和name作为其状态。我们使用Employee作为哈希表中的键。所以我们以满足hashcode和equals方法两种方式的方式覆盖哈希码。所以需要相同的方法。
我知道我在这里遗漏了一些东西。寻找它。
答案 0 :(得分:3)
问题在于,您无法保证(作为一般条件)哈希码始终是唯一的。
您可以创建一个单独的类,例如Employee应该由employeeId唯一标识。没有理由你的哈希码不能简单地return employeeId;
- 你会保证这种方式的唯一性。
但是,一般的对象会有更多。考虑一个坐标类
class Coordinate {
int x;
int y;
int z;
public boolean equals(Object o) {
if(o instanceof Coordinate) {
Coordinate c = (Coordinate)o;
return x == c.x && y == c.y && z == c.z;
}
return false;
}
public int hashCode() {
return x ^ y ^ z;
}
}
你的x y和z会产生2 ^ 96种不同的唯一性组合,但只有2 ^ 32种可能的哈希码。例如,1,2,3对3,2,1都是相同的。现在你可以改进这个以使哈希码像
public int hashCode(){ int c = x; c * = 31 + y; c * = 31 + z; 返回c; }
但这不会解决问题 - 您仍然可以提出数千种会导致哈希码冲突的组合。
但不要害怕 - 有你所描述的东西:它们被称为Perfect Hashes
答案 1 :(得分:3)
是的,你错过了什么。
首先:hashCode返回一个int,因此只能返回2 ^ 32个不同的值。因此,需要等于能够区分具有相同哈希码的值。
第二:哈希表使用hashCode模数它维护的桶数。因此,即使两个键具有不同的hashCodes,它们也可能属于同一个桶,并且必须使用equals来区分它们。
答案 2 :(得分:2)
您缺少的是某些数据无法用有限整数唯一表示。 String
就是一个例子。
此外,当hashCodes相同时,equals
仅使用 。元素被放入“桶”中,通常覆盖数百万个可能的hashCode值(使用模运算符)。因此,即使每个可能的对象都有一个唯一的hashCode,你仍然需要仔细检查所有内容。
答案 3 :(得分:2)
问题是hashCode()
返回int
,并且只有2 ^ 32个不同的哈希码。因此,对于具有超过2 ^ 32个不同状态的类(即几乎所有内容),无法避免为某些对象返回相同的哈希码,即使它们不相等。
答案 4 :(得分:0)
所以我的问题是我们在equals方法中所做的工作,我们可以消除它并在hashcode方法中放入相同类型的逻辑,我们提供不同的hashcode(取决于我们在equals方法中放置的逻辑)。
equals
方法用于防止将重复键插入Map
(如果您使用API文档);这包括HashMaps和HashTables。另一方面,hashcode
方法用于优化查找,但不能依赖于比较两个键的相等性,因为存在哈希冲突的可能性。 Map
文档明确指出:
实现可以自由地实现优化,从而避免使用equals调用,例如,首先比较两个键的哈希码。
如果密钥之间发生哈希冲突,则单个存储桶将为两个不同的密钥存储两个或多个值,并且必须顺序遍历存储桶以查找与密钥匹配的值,这是最坏的情况。这就是使用hashcode
进行比较的优化原因,因为匹配键的实际值只能通过equals方法获得。请注意,这假设用于计算哈希码的相同字段也用于比较相等。