我知道为每个对象返回相同的值是低效的,但它是为不同实例返回不同值的最有效方法吗?
如果每个对象获得不同的hashCode值,那么这不就像将它们存储在ArrayList中一样吗?
答案 0 :(得分:4)
hashCode
必须与equals
一致,这是第一优先。如果没有两个对象相等,那么这是可取的。请记住,如果您的对象具有超过32位的状态,理论上不可能提供完美分布的哈希码。
答案 1 :(得分:3)
不,实际上并非如此。
假设您的对象将被存储到HashMap中(或者Set ...无关紧要,为简单起见,我们在这里使用HashMap),您希望hashCode方法返回一个结果尽可能均匀地分配对象的方式。
Hashcode 应该对于不相等的对象是唯一的,尽管你不能保证这一直是真的。
另一方面,如果a.equals(b)
为真,那么a.hashCode() == b.hashCode()
。这称为Object Contract。
除此之外,还存在性能问题。每当两个不同的对象具有相同的hashCode时,它们就会被映射到HashMap中的相同位置(也就是说,它们会发生冲突)。这意味着HashMap实现必须处理这种冲突,这比简单地存储和检索条目要复杂得多。
还有很多算法依赖于值在Map上均匀分布的事实,并且当碰撞次数增加时性能会迅速恶化(某些算法假定完美的散列函数,这意味着不会发生任何碰撞,没有两个不同的值被映射到Map上的相同位置。
这方面的好例子是概率算法和数据结构,例如Bloom Filters(使用这些天看似时尚的例子)。
答案 2 :(得分:1)
您希望hashCode()尽可能多样化以避免冲突。如果没有冲突,则每个键或元素将自己存储在底层数组中。 (有点像ArrayList)
问题是即使hashCode()不同,你仍然可以得到冲突。发生这种情况是因为您没有针对每个可能的hashCode的存储桶,并且此值必须减小到更小的范围。例如你有16个桶,范围是0到15.它是如何做到这一点很复杂,但我相信你可以看到,即使所有的hashCodes都不同,它们仍然会导致碰撞(尽管不太可能)
这是拒绝服务攻击的一个问题。通常字符串具有较低的冲突率,但是您可以故意构造具有相同哈希码的字符串。这个问题给出了一个字符串列表,其hashCode为0 Why doesn't String's hashCode() cache 0?
答案 3 :(得分:0)
hashCode()方法不适合在ArrayList中放置对象。 虽然它每次都为同一个对象返回相同的值,但是两个对象很可能具有相同的哈希码。
因此,在将项目存储在例如HashMap中时,hashCode方法用于关键Object。
答案 4 :(得分:0)
HashMap类的主要数据结构如下:
Entry[] table;
值得注意的是,Entry类(实现Map.Entry的静态包保护类)实际上是一个链表样式结构。
当您尝试放置元素时,首先计算密钥的哈希码,然后将其转换为桶号。 “bucket”是上述数组的索引。
找到存储桶后,在该存储桶内部进行线性搜索以获得确切的密钥(如果您不相信我,请查看HashMap代码)。如果找到,则替换该值。如果不是,则将键/值对附加到该桶的末尾。
由于这个原因,hashcode()值不一定是唯一的,但是,它们越独特且均匀分布,你就越有可能在值之间均匀分配值。如果你的hashcode()方法为所有实例返回相同的值,它们都会在同一个桶中结束,因此将get()方法渲染为一个长线性搜索,产生O(N)
值越分散,桶越小,因此线性搜索组件越小。唯一值将产生恒定的时间查找O(1)。