在重新equals方法时为啥要重写hashCode方法?
重写的原则是:两个对象根据equals方法相等,则两个对象hashCode产生同样的整数结
果。
其实重写hashCode方法是为了保证一些基于散列的集合能正常工作,这样集合包括
(HahsMap,HashSet,HashTable)。因为此类集合是利用hash算法与equals来区分对象的等同性。比如:对类 Test重写了equals方法,没有重写hashCode方法,意味着当Test类的两个实例a和b,在逻辑上相同(a.equals(b)==true),但是两个实例的hashCode不同。当定义一个Map对象:
Map<Test,String> map=new HashMap<Test,String>();
map.put(a,"this is Test object");
此时若系统通过map.get(b);来获得“this is Test object”,但返回的确是null。这是因为
map对象将a对象放入一个散列桶中,而get方法却在另一个散列桶中查询,即便两个散列码同时在一个散列桶中,也会因为散列码不同而找不到。散列码不匹配就没有必要验证对象的等同性,所以此处找不到返回null。由此可见,重写hashCode方法是很有必要的,因为你不知道你定义的类不会被别人放入hash机制的集合中。
下面是重写equals和hashCode通用的方式:
此处摘录《Effective java》 和转载:http://zhangjunhd.blog.51cto.com/113473/71571/
1.设计equals()
[1]使用instanceof操作符检查“实参是否为正确的类型”。
[2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。
[2.1]对于非float和double类型的原语类型域,使用==比较;
[2.2]对于对象引用域,递归调用equals方法;
[2.3]对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较;
[2.4]对于double域,使用Double.doubleToLongBits(adouble) 转换为int,再使用==比较;
[2.5]对于数组域,调用Arrays.equals方法。
2.设计hashCode()
(散列函数最好的结果是把集合中不相同的实例均匀的分不到所有可能的散列值上。当然这个很难实现)
[1]把某个非零常数值,例如17,保存在int变量result中;
[2]对于对象中每一个关键域f(指equals方法中考虑的每一个域):
[2.1]boolean型,计算(f ? 0 : 1);
[2.2]byte,char,short型,计算(int);
[2.3]long型,计算(int) (f ^ (f>>>32));
[2.4]float型,计算Float.floatToIntBits(afloat);
[2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3];
[2.6]对象引用,递归调用它的hashCode方法;
[2.7]数组域,对其中每个元素调用它的hashCode方法。
[3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c;
[4]返回result。
示例:
package com.zj.unit; import java.util.Arrays; public class Unit { private short ashort; private char achar; private byte abyte; private boolean abool; private long along; private float afloat; private double adouble; private Unit aObject; private int[] ints; private Unit[] units; public boolean equals(Object o) { if (!(o instanceof Unit)) return false; Unit unit = (Unit) o; return unit.ashort == ashort && unit.achar == achar && unit.abyte == abyte && unit.abool == abool && unit.along == along && Float.floatToIntBits(unit.afloat) == Float .floatToIntBits(afloat) && Double.doubleToLongBits(unit.adouble) == Double .doubleToLongBits(adouble) && unit.aObject.equals(aObject) && equalsInts(unit.ints) && equalsUnits(unit.units); } private boolean equalsInts(int[] aints) { return Arrays.equals(ints, aints); } private boolean equalsUnits(Unit[] aUnits) { return Arrays.equals(units, aUnits); } public int hashCode() { int result = 17; result = 37 * result + (int) ashort; result = 37 * result + (int) achar; result = 37 * result + (int) abyte; result = 37 * result + (abool ? 0 : 1); result = 37 * result + (int) (along ^ (along >>> 32)); result = 37 * result + Float.floatToIntBits(afloat); long tolong = Double.doubleToLongBits(adouble); result = 37 * result + (int) (tolong ^ (tolong >>> 32)); result = 37 * result + aObject.hashCode(); result = 37 * result + intsHashCode(ints); result = 37 * result + unitsHashCode(units); return result; } private int intsHashCode(int[] aints) { int result = 17; for (int i = 0; i < aints.length; i++) result = 37 * result + aints[i]; return result; } private int unitsHashCode(Unit[] aUnits) { int result = 17; for (int i = 0; i < aUnits.length; i++) result = 37 * result + aUnits[i].hashCode(); return result; } }
相关推荐
在Java编程中,当我们重写`equals()`方法时,通常也需要重写`hashCode()`方法。这是因为`equals()`和`hashCode()`方法在Java集合框架中扮演着重要的角色,特别是在使用`HashMap`、`HashSet`等基于哈希表的集合类时。...
equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.
- 为了避免哈希冲突带来的性能问题,在覆盖`equals()`方法的同时,通常也需要覆盖`hashCode()`方法。 #### 实现示例 以下是一个简单的类`Person`,展示了如何正确覆盖`equals()`和`hashCode()`方法: ```java ...
7. **条目7:覆盖equals时总要覆盖hashCode(Override equals() and hashCode() in pairs)** 当重写equals()方法时,必须同时重写hashCode(),以确保一致性,否则会影响集合类的行为。 8. **条目8:始终重写...
为了实现元素的唯一性,`Set`接口要求覆盖`equals`方法,使其能够根据元素的实际内容来进行比较。 - **内容比较**: 在`Set`接口的不同实现中,通常会根据元素的属性或内容来进行比较。例如,在`String`类中,`...
- **一致性**:在覆盖`equals()`方法时,也需要确保同时覆盖`hashCode()`方法,并且两个方法的实现要保持一致,以避免潜在的哈希冲突问题。 - **性能考量**:在设计`hashCode()`方法时,应尽可能选择分布均匀的哈希...
2. 对于不相等的对象,`equals`返回`false`时,`hashCode`应尽可能不同,以减少哈希冲突。 3. `equals`方法的重写应遵循自反性、对称性、传递性和一致性原则。 4. 如果重写了`equals`,那么通常也应重写`hashCode`,...
在Java编程语言中,`hashCode`和`equals`方法是非常重要的概念,它们在处理对象的比较、存储以及检索时扮演着关键角色。本文将深入探讨这两个方法之间的区别,并通过具体例子来说明它们的重要性。 #### 一、`equals...
首先,根据键的 `hashCode` 定位到对应的桶,然后遍历桶中的条目,如果找到一个条目的键与要插入的键 `equals` 并且哈希值相同,那么就会覆盖旧的值,否则会在桶中添加新的条目。如果两个键的 `equals` 返回 true 但...
因此,重写 `equals()` 时务必考虑 `hashCode()`。不一致的 `equals()` 和 `hashCode()` 实现可能导致违反哈希表的语义,影响程序的正确性和性能。Java 文档明确指出,如果你重写了 `equals()`,也应该重写 `...
4. **覆盖两者**:如果只覆盖 `equals()` 不覆盖 `hashCode()`,可能会导致集合行为异常,因为哈希表依赖于两者的一致性。 在具体实现时,可以使用对象属性的哈希码组合来生成自定义的哈希码,例如: ```java @...
jv-equals-hashcode 给定的类—矩形。 覆盖它的方法equals()和hashCode()所以equals()通过其字段(颜色,宽度和长度equals()比较Rectangle对象。 还要确保hashCode()遵循equals和hashcode之间的约定。
此外,Object 类的设计是为了扩展,它提供了一些非 final 方法,如 equals、hashCode、toString、clone 和 finalize,这些方法都有通用的约定,需要在子类中被覆盖(override)。如果不遵守这些约定,依赖这些约定的...
- 如果类的实例不会与其他类型对象相等(即没有覆盖`equals()`),则无需重写`hashCode()`。 综上所述,正确实现`hashCode()`方法对于优化Java应用程序的性能和正确性至关重要。在设计和实现类时,必须考虑到`...
5. **覆盖`hashCode()`**:如果两个对象根据`equals()`方法比较相等,它们的`hashCode()`方法必须返回相同的值。反之不成立,因为不同的对象可能有相同的`hashCode()`。 遵循这些准则,我们可以编写符合预期的`...
五、覆盖equals()时的注意事项 当重写equals()方法时,务必同时重写hashCode()方法,以保持equals()和hashCode()的一致性。此外,要遵循以下原则: 1. 自反性:对于任何非null引用x,x.equals(x)应返回true。 2. ...