Java Hashcode和equals方法契约
我知道,当我们重写Java Hashcode和equals方法契约,java,equals,hashcode,Java,Equals,Hashcode,我知道,当我们重写equals()方法时,我们也需要重写hashcode()方法 但我不明白为什么我们必须这样做 在Joshua Bloch的书中明确指出,我们必须这样做,因为当我们处理基于哈希的集合时,满足哈希代码契约是至关重要的,我承认这一点,但如果我没有处理基于哈希的集合呢 为什么仍然需要它?因为这就是它的本意: 每当a.equals(b)时,a.hashCode()必须与b.hashCode()相同 在某些用例中,您不需要hashcode(),大多数情况下都是自编场景,但您永远无法确定
equals()
方法时,我们也需要重写hashcode()
方法
但我不明白为什么我们必须这样做
在Joshua Bloch的书中明确指出,我们必须这样做,因为当我们处理基于哈希的集合时,满足哈希代码契约是至关重要的,我承认这一点,但如果我没有处理基于哈希的集合呢
为什么仍然需要它?因为这就是它的本意: 每当a.equals(b)时,a.hashCode()必须与b.hashCode()相同
在某些用例中,您不需要
hashcode()
,大多数情况下都是自编场景,但您永远无法确定,因为如果使用equals()
数据结构,例如HashMap
,则实现可以而且可能也依赖于hashcode()
,这取决于契约
HashMap通过使用hashcode对条目进行bucketize来实现神奇的性能属性。放置在映射中具有相同hashcode()
值的每个项目都将放置在同一个bucket中。这些“冲突”是通过使用equals()
在同一个bucket内进行比较来解决的。换句话说,hashcode用于确定映射中可能相等的项的子集,并以这种方式快速消除绝大多数项的进一步考虑
这仅在相等的对象放在同一个bucket中时有效,只有当它们具有相同的hashcode时才能确保这一点
注意:在实践中,冲突的数量比上面可能暗示的要高得多,因为使用的bucket数量必然比可能的hashcode值的数量小得多。为什么要覆盖Equals?
使用equals
方法希望找出它们在逻辑上是否等价,而不是
它们是否引用同一对象
现在来看HashCode
哈希函数被调用以生成哈希代码每次都应返回相同的哈希代码,
当函数应用于相同或相等的对象时。换句话说,两个
相等的对象必须一致地生成相同的哈希代码
对象类
提供的HashCode的实现不是基于逻辑等价性
因此,现在如果您不重写hashCode
而是重写equals
,那么根据您的说法,两个对象是相等的,因为它们将通过equals()
测试,但根据Java,它们不是
后果:
设置
开始允许重复李>
Map#get(key)
将不会返回正确的值李>
等等许多其他的后果
根据约书亚·布洛赫的书
错误的一个常见来源是未能覆盖哈希代码
方法必须在每个重写的类中重写哈希代码
等于。不这样做将导致违反一般规则
Object.hashCode的契约,这将阻止您的类
与所有基于哈希的集合一起正常运行,
包括HashMap、HashSet和Hashtable
重写equals时未能重写hashcode违反了Object.hashcode的约定。但如果您仅在非基于散列的集合上使用对象,则这不会产生影响
但是,如何预防;其他开发人员正在这样做。另外,如果一个对象符合集合元素的条件,那么最好为所有集合提供支持,不要在项目中包含未完成的对象。这将在将来的任何时候失败,并且您将因为在实现时没有遵循联系人而被抓获:)这个问题在SO中被回答了很多次,但我仍将尝试回答这个问题
为了完全理解这一概念,我们需要理解hashcode和equals的目的、它们是如何实现的,以及这个契约到底是什么(当equals被重写时hashcode也应该被重写)
equals方法用于确定对象的相等性。对于基元类型,很容易确定相等性。我们可以很容易地说int 1总是等于1。但是这个相等的方法谈论的是对象的相等。对象相等性取决于实例变量或任何其他参数(完全取决于实现-您希望如何比较)
如果我们想要一些定制的比较,我们需要重写这个相等的方法,假设我们想要说两本书是相同的,如果它们有相同的标题和作者,或者我可以说两本书是相等的,如果它们有相同的ISBN
hashcode方法返回对象的哈希代码值。对象哈希代码的默认实现为不同的对象返回不同的整数。该整数是根据对象的内存地址计算的
因此,我们可以说equals方法的默认实现只是使用hashcode检查对象的相等性。但是对于书的例子,我们需要不同的方法
同样,只要相等,相等的对象必须产生相同的哈希代码,但是不相等的对象不需要产生不同的哈希代码
如果不使用基于哈希的集合,您可以打破契约,不需要重写hashcode方法-因为您不会在任何地方使用默认实现,但我仍然不建议您这样做,并且会说,当您将来将这些东西放入集合时,您可能需要它,因为任何两个相等的对象都必须,通过