java中重写equals方法要重写hashCode方法

来源:互联网 发布:水泥凝结时间测定数据 编辑:程序博客网 时间:2024/06/05 17:38

在java笔试和面试中,经常会遇到“重写equals方法是否要重写hashCode方法“的问题。正好最近看到《effective java》中的这个地方,标题就是“覆盖equals方法总要覆盖hashCode方法”。

先看代码,本地也写了个demo,创建一个对象,先不重写hashCode方法,然后结合基于散列的集合使用,对于满足equals方法的相等的对象,看是否真的是相等的对象。

这段代码没有重写hashCode方法:

class TestObj {int i, j;public int getI() {return i;}public void setI(int i) {this.i = i;}public int getJ() {return j;}public void setJ(int j) {this.j = j;}TestObj(int i, int j) {super();this.i = i;this.j = j;}@Overridepublic boolean equals(Object obj) {if (this == obj){return true;}if (obj == null){return false;}if(!(obj instanceof TestObj)){return false;}TestObj other = (TestObj) obj;if (i == other.i && j == other.j){return true;}return true;}}
接下来我们使用这个TestObj对象,书写一个测试类:

@Test public void Test1(){ Map<TestObj, String> map = new HashMap<TestObj, String>();TestObj t1 = new TestObj(1, 2);TestObj t2 = new TestObj(1, 2);map.put(t1, "obj");System.out.println(t1.equals(t2));System.out.println("t1-->" + t1.hashCode());System.out.println("t1-->" + t2.hashCode());System.out.println(map.get(t2)); }


控制台输出结果是“true”、“null”。t1和t2是满足equals方法的相同的对象,由于没有重写hashCode方法,打印出来的hashCode的值也不同,对象的散列码不同,从而获取的值为空。下面把这个类的hashCode的方法重写,如下:

@Overridepublic int hashCode() {final int f = 31;int result = 1;result = f * result + i;result = f * result + j;return result;}
添加了重写hashCode方法后,在运行控制台输出的结果是“true”、“obj”。此时是真正意义的相等,相等的对象实例具有相同的散列码。

在Object规范中,有这样的判定描述:

1、在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数。在一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。

2、如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

3、如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。

由此可见,在没有重写hashCode方法,即使实例对象equals方法是相等的,由于两者的hashCode值不同,所两个实例对象并不是相等的,所以获取到的值是为空。只有在重写了hashCode后,能够获取到对应的value值。

又写了一个Test2,此时是TestObj类是没有重写hashCode方法的,在map的添加角度也可以看出,代码如下:

@Test public void Test2(){ Map<TestObj, String> map = new HashMap<TestObj, String>();TestObj t1 = new TestObj(1, 2);TestObj t2 = new TestObj(1, 2);map.put(t1, "obj");map.put(t2, "obj2");System.out.println(t1.equals(t2));System.out.println("t1-->" + t1.hashCode());System.out.println("t1-->" + t2.hashCode());System.out.println(map.get(t2));System.out.println(map.size()); }

我们知道map集合的key是唯一的,即使在添加相同的key,map只会覆盖最后一次添加key对应的value值。上面的案例,没有重写TestObj类的hashCode方法,控制台的输出依次是“true”、“t1-->1245607833”、“t1-->1260258275”、“obj2”、“2”,可以看出,map集合是人为两个对象并不相等,对于hashCode可以看出,确实不相等,所以打印出来的长度为2.

接下来加上TestObj类的hashCode方法,这是打印的两者的hashCode值是相等的,map的长度是1。这样就对了,两个相等的对象,map添加是取最后一次对应value值。

理论上来说,在比较对象是否相等时,是先比较两者的hashCode值相等,如果hashCode的值相等,那么两个对象是相等的,相反,hashCode值不等,两个对象也就不等。当然,这个要看你的hashCode方法是怎么写的。


阅读全文
0 0