Java中的hashCode二

 equals方法和hashCode方法

  在有些情况下,我们在设计一个类的时候,会重写equals 方法,比如String类,但是千万要注意,在重写equals 方法的同时,必须重写hashCode方法,为什么?

  下面看一个例子:

package com.zd.test;

public class People {

	private String name;
	private int age;
	
	public People(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public boolean equals(Object paramObject) {
		// TODO Auto-generated method stub
		if(this == paramObject){
			return true; //先检查是否其自反性,后比较paramObject是否为空。这样效率高
		}
		if(paramObject == null){
			return false;
		}
		if(paramObject instanceof People){
			People temp  = (People)paramObject;
			if(temp.getName().equals(this.name) && temp.getAge() == this.age){
				return true;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}
}


package com.zd.test;

import java.util.HashMap;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		People p1 = new People("jack", 12);
		System.out.println(p1.hashCode());
		
		HashMap<People, Integer> hashMap = new HashMap<People, Integer>();
		hashMap.put(p1, 1);
		
		System.out.println(hashMap.get(new People("jack", 12)));
	}

}

   在这里只重写了equals 方法,也就是说如果俩个People对象,如果他们姓名和年龄相等,则认为同一个人。

   这段代码的意愿是输出为“1”,但是事实上他输出为 “null“。为什么?原因就在于重写equals方法的同时没有重写hashCode方法。

   虽然通过重写equals方法使得逻辑上姓名和年龄相同的俩个对象为相等的对象,但是要知道默认情况下,hashCode方法是将对象的存储地址进行映射。那么上述代码输出为

”null“就不奇怪了。原因很简单,p1指向对象和

System.out.println(hashMap.get(new People("jack", 12)));

 这句话中的 new People("Jack", 12) 不是同一个对象,他们的存储地址肯定不同。

  下面是HashMap的get方法的具体实现:

public V get(Object paramObject)
  {
    if (paramObject == null) {
      return getForNullKey();
    }
    Entry localEntry = getEntry(paramObject);
    return null == localEntry ? null : localEntry.getValue();
  }

   所以在hashMap 进行get操作的时候,因为得到的hashcode值不同(注意:上述代码在某些情况下会得到相同的hashCode,不过这种概率比较小,因为虽然俩个对象的地

址不同,但是也有可能获得相同的hashCode),所以导致在get方法中for循环不会执行,直接返回null。

  因此如果想要上述代码输出1 ,很简单,只要重写hashCode方法,让hashCode方法和equals 方法保持逻辑一致。

package com.zd.test;

public class People {

	private String name;
	private int age;
	
	public People(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getAge() {
		return age;
	}
	
	public void setAge(int age) {
		this.age = age;
	}
	
	@Override
	public int hashCode() {
		// TODO Auto-generated method stub
		return name.hashCode() * 37 + age;
	}
	
	@Override
	public boolean equals(Object paramObject) {
		// TODO Auto-generated method stub
		if(this == paramObject){
			return true; //先检查是否其自反性,后比较paramObject是否为空。这样效率高
		}
		if(paramObject == null){
			return false;
		}
		if(paramObject instanceof People){
			People temp  = (People)paramObject;
			if(temp.getName().equals(this.name) && temp.getAge() == this.age){
				return true;
			}else{
				return false;
			}
		}else{
			return false;
		}
	}
}

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

  如果俩个对象根据equals 方法比较是相等的,则hashCode方法不一定得返回相同的整数;

  如果 俩个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。

  设计hashCode时最重要的因素是:无论何时,对同一个对象调用hashCode都应该产生同样的值,如果在向一个Map中put时用的是一个值,而get的时候又是另一个值,那么

就无法获取到该对象了。
 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值