如果对象值相同(x.equals(y)==true),那么是否可以有不同的hash code?

  一.这个答案是可以的。

  对于这种情况,我们可以称这两个对象值在逻辑上可能是相等的,但是他们是两个不同的对象实例。如果x.equals(y)==true,而hashcode的值不相等,那么这个违反了javaSE6的object规范:如果两个对象根据equals(object)方法比较相等,那么调用两个对象中的任意一个的hashcode方法,返回的值相等。

下面在来看下这个例子,能更深刻的反应出上面提出的问题:

public class HashcodeClass1 {

	public int num1;
	public int num2;
	public int num3;
	
	public HashcodeClass1(int num1,int num2,int num3){
		this.num1 = num1;
		this.num2 = num2;
		this.num3 = num3;
	}
	
	@Override
	public boolean equals(Object o){
		if(o==this)
			return true;
		if(!(o instanceof HashcodeClass1))
			return false;
		HashcodeClass1 hc = (HashcodeClass1)o;
		if(hc.num1 == num1&&hc.num2 == num2&&hc.num3==num3)
			return true;
		return false;
	}
	
	public static void main(String[] args) {
		HashcodeClass1 code1 = new HashcodeClass1(1,2,3);
		HashcodeClass1 code2 = new HashcodeClass1(1,2,3);
		//通过equals方法返回的值是true,但是这两个对象的hashcode并不相等
		System.out.println(code1.equals(code2));
		System.out.println("the code1's hashcode is :"+code1.hashCode());
		System.out.println("the code2's hashcode is :"+code2.hashCode());
	}
}

通过这个例子,我们可以看到两个通过equals方法比较的两个对象值是true的时候,他们的hashcode值并不一定相等。之所以出现了这个情况是因为这个类重覆盖了equals方法,但是没有覆盖hashCode的方法。所以请记住这一条,覆盖了equals方法的时候,一定要覆盖hashCode方法(effective-java中的第9条)。

  二.下面的代码放到main方法中,我们会发现,虽然这两个对象的equals值返回true,但是并不是真正意义上的相等。

//再次对比两个对象是否相等
		Map map = new HashMap<HashcodeClass1,String>();
		map.put(code1, "code1");
		System.out.println("通过code2来获得code1:"+map.get(code2));//这个结果是null,也就是,没有能获得code1,虽然通过equals方法返回的值是true
通过code2来获得code1,结果却是空,为什么会这样呢?这个还是跟hashCode方法有关,因为hashCode方法没有被覆盖,造成hash code值不一样,所以map通过put方法将code1对象放到一个散列桶中,而map的get方法却在另一个散列桶中寻找这个对象,因此出现找不到即为空,即使是刚好get方法查找的散列桶是map的put的方法使用的,hashMap对此作了一个优化,将每一个对象相关的散列码缓存起来,如果散列码不相同,也不会检验对象的等同性。

三.如何覆盖hashCode方法:关于如何覆盖hashCode,下面是一个hashCode方法的例子,针对的是上面的类写的。

  

	@Override
	public int hashCode(){
		int result = 15;
		result = 31*result + num1;
		result = 31*result + num2;
		result = 31*result + num3;
		return result;
	}

这个方法比较简单,但同时也比较实用,这里面涉及到几个取值的问题,第一个为什么result的初始值设为15而不是0,是因为如果类没有相应的域,那么返回的hashCode的值始终未0,则没有比较的意义,而且在object的javaSE6的规范中有这么一条,如果两个对象不等,那么对象返回的hashCode值最好不相等。第二个用31这个奇素数乘以result,因为31有这么几个特性,可以通过一位和减法俩代替乘法,可以获得更好的性能:31*i==(i<<5)-i,而且现代的vm可以自动完成这种优化。

本篇针对问题的很多概念以及观点采自effective-java中的第9条,大家有兴趣可以去看看effective-java上面的关于这些的概念。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值