关于重写类的hashcode和equals方法的注意点

首先们先打个比方 现在有一个集合HashSet 这个集合里放的是一个Person类的实例对象 这个Person类重写了hashcode和equals方法

Person类的代码如下:

@Override
public boolean equals(Object obj) {
  // TODO Auto-generated method stub
  if(this==obj){
   return true;
  }
  if(obj instanceof Person){
   Person person = (Person)obj;
   if(this.name.equals(person.getName()) && (this.age==person.getAge())){
    return true;
   }else{
    return false;
   }
  }
  return false;
}
@Override
public int hashCode() {
  // TODO Auto-generated method stub
  return this.name.hashCode()*30+this.age*23;
}

 

我们重写的hashcode方法中Person属性的name和age参与了hashcode得计算

下面我向set集合里添加几个Person类的实例对象

Set<Person> persons = new HashSet<Person>();
  Person person1 = new Person("cdx",23);
  Person person2 = new Person("cdx1",24);
  Person person3 = new Person("cdx2",25);
  Person person4 = new Person("cdx",23);
  persons.add(person1);
  persons.add(person2);
  persons.add(person3);
  persons.add(person4);
  persons.add(person1);
  //应该是3 三个元素因该是person1 person2 person3
  //当我们放person4时会判断equals和后hashcode和peson1都相同就不会再向里加了
  //而不是把以前的给覆盖了
  System.out.println(persons.size());
  //现在我来改变person1的age值然后移除person1 来看看我们能不能移除person1
  person1.setAge(21);
  persons.remove(person1);
  //打印出来是3
  System.out.println(persons.size());

 当我们对类的属性参与hashcode运算时我们不能再随意修改参与运算的参数的值了 因为当我们在向set中放置person时 java虚拟机会根据每个对象的计算出的hashcode值来判断把对象放置在内存hash的哪个区域 当我们放进去之后我们去修改某个参与hashcode计算的属性的值时 这个person1的hashcode的就会改变 当我们去移除他的时候 会根据改变后的hashcode值去hash的某个区域去寻找对象然后移除 但是这时因为hashcode值被改变 所以在hash区域里根本找不到对应的hash值 所以以前的对象根本没有移除掉

 

 

在重写任何类的equals方法是必须遵循以下几点:

1、对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

2、反射性:x.equals(x)必须返回是“true”。

3、类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。 

4、还有一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

5、任何情况下,x.equals(null),永远返回是“false”; 

 

 

在重写任何类得hashcode方法是必须遵循以下几点:

1、在Java应用的同一次执行过程中,同一对象被多次调用,则他们的hashcode值必然相同。而对于同一个应用的两次不同的调用,它们的Hashcode值可以相同,也有可能不同。

2、对于两个对象来说,如果他们的equals方法比较返回true,那么这两个对象的hashcode必然相同。这也解释了为什么String类中,如果两个对象的equals方法相同,则他们的hashcode值一定相同。

3、对于两个对象来说,如果使用equals方法返回为false,则他们的hashcode的值有可能相等也可能不等,(如果不同会提高性能,因为在集合中类判断两个对象是否相等,如果其hashcode不等就直接不用判断equals方法了)

4、对于Object对象来说,不同的Object对象的hashcode是不同的,它们返回的是对象的地址,equals返回的也是对象的地址。所以在自己定义的类中如果要添加到集合对象中,最好是要重写hashcode和equals方法,不然会自动继承自Object类中的两个方法根据对象地址来判断。在重写自己定义的类时,通常是在类中的根据某个值如name.hashcode();来进行判断。

以HashSet 为例,

 

当我们使用HashSet时,hashCode()方法就会被得到调用,判断已经存储在集合中的对象的hashCode值是否与所增加

 

对象的hashCode值一致,如果“不一致”则直接加进去(不用比较equals()提高效率),如果一致,则进行equals方法的比较,如果返回true,表明
集合里面已经有这个对象,不能添加进去了。如果是false表是集合里面没有这个对象,则可以加进去。所以我们在重写hashcode()或者equals()
方法的任何一个方法时,必须重写另外一个。
自己手工写了一个类来重写这两个方法:
?[Copy to clipboard] Download People.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
 *
 * People  手工重写hashcode方法和equals方法  根据name来判断 两个对象是否相等。
 * 2011-7-12 上午09:09:56
 *
 * @version 1.0.0
 *
 */
class People {
	private String name;
 
	public People(String name){
		this.name=name;
	}
	@Override
	public boolean equals(Object obj) {
 
		// TODO Auto-generated method stub
		//如果是自己
		if(this==obj){
			return true ;
 
		}
		//如果是空
		if(obj==null ){
			return false;
		}
		//比较两个People的名字是否相同
		if(obj!=null && obj instanceof People){
			if(((People)obj).name.equals(this.name))
				return  true ;
 
		}
		return false;
 
	}
 
	@Override
	public int hashCode() {
 
		// TODO Auto-generated method stub
		//String的hashcode本来就是用来比较两个字符是否相等
		return  name.hashCode();
 
	}
 
}

其他相关问题:

       那么在String中的hashcode是怎么定义的呢?在String的API中我们可以看到这样一个公式: s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1] 使用int 算法,这里s[i] 是字符串的第i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希码为0。)这说明String 中的hashcode 返回的并不是在内存中的地址,如果两个字符串的内容相同(equals为true),则其hashcode值必然就相同,equal为true。同理经过傻蛋测试在Integer类中和String类似,hashcode方法和equals方法也是判断其包裹的原始值的内容是否相同。

总结:在Java中,String 、Math、还有Integer、Double。。。。等这些封装类重写了Object中的equals()方法,让它不再比较其对象在内存中的地址,而是比较对象中实际包含的整数的值,即比较的是内容。再强调一次,Object的equals()方法比较的是地址值,所以Object equals相等时,其hashcode必然相等,因为都是对象的地址,所以自己定义的类如果要加入到集合类中一定要记得重写这两个方法。

      在Eclipse中重写hashcode和equals方法使相当方便的,只需要右键->source->Generate hashcode() and equals()便可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值