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

在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;
	}

	@Override
	public 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的方法重写,如下:

@Override
	public 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值