为什么重写equals 和hashCode方法,如何重写

一.为什么要重写

Java中的超类Object类中定义的equals()方法是用来比较两个引用所指向的对象的内存地址是否一致

Object类中equals()方法的源码

public boolean equals(Object obj) {

       return (this == obj);

}

********************************************************************

Object类中的hashCode()方法,用native关键字修饰,说明这个方法是个原生函数,也就说这个方法的实现不是用java语言实现的,是使用c/c++实现的,并且被编译成了DLL,由java去调用,jdk源码中不包含。对于不同的平台它们是不同的,java在不同的操作系统中调用不同的native方法实现对操作系统的访问,因为java语言不能直接访问操作系统底层,因为它没有指针。

这种方法调用的过程:

1、在java中申明native方法,然后编译

2、用javah产生一个  .h  文件

3、写一个 .cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(其中又包含了jdk带的jni.h文件);

4、将.cpp文件编译成动态链接库文件

5、在java中用System.loadLibrary()文件加载第四步产生的动态链接库文件,然后这个navite方法就可被访问了

Java的API文档对hashCode()方法做了详细的说明,这也是我们重写hashCode()方法时的原则【Object类】

重点要注意的是:

a.  在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值

b.  如果两个对象equals()返回值为true,则他们的hashCode()也必须返回相同的int值

c.  如果两个对象equals()返回值为false,则他们的hashCode()返回值也必须不同

public native int hashCode();

 

现在到了说正题了,为什么要重写

我们在定义类时,我们经常会希望两个不同对象的某些属性值相同时就认为他们相同,所以我们要重写equals()方法,按照原则,我们重写了equals()方法,也要重写hashCode()方法,要保证上面所述的b,c原则;所以java中的很多类都重写了这两个方法,例如String类,包装类

 

什么情况下需要重写hashCode()方法和equals()方法:

当我们自定义的一个类,想要把它的实例保存在集合中时,我们就需要重写这两个方法;集合(Collection)有两个类,一个是List,一个是Set

List:集合中的元素是有序的,可以重复的

Set:无序,不可重复的

以HashSet来说明:

HashSet存放元素时,根据元素的hashCode值快速找到要存储的位置,如果这个位置有元素,两个对象通过equals()比较,如果返回值为true,则不放入;如果返回值为false,则这个时候会以链表的形式在同一个位置上存放两个元素,这会使得HashSet的性能降低,因为不能快速定位了。还有一种情况就是两个对象的hashCode()返回值不同,但是equals()返回true,这个时候HashSet会把这两个对象都存进去,这就和Set集合不重复的规则相悖了;所以,我们重写了equals()方法时,要按照b,c规则重写hashCode()方法!

二.如何重写

比较两个Java对象时, 我们需要覆盖equals和  hashCode
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class User{      
  2.     private String name;  
  3.     private int age;  
  4.     private String passport;  
  5.   
  6.     //getters and setters, constructor  
  7. }  

在比较结果时:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. User user1 = new User("mkyong"35"111222333");  
  2. User user2 = new User("mkyong"35"111222333");  
  3.   
  4. System.out.println(user1.equals(user2)); // false  

下面我们将介绍几种常用方法:

 1.经典方式

这种17和31散列码的想法来自经典的Java书籍——《Effective Java》第九条。下面我们来看看是如何实现的...
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. public class User {  
  2.     private String name;  
  3.     private int age;  
  4.     private String passport;  
  5.     //getters and setters, constructor  
  6.     @Override  
  7.     public boolean equals(Object o) {  
  8.         if (o == thisreturn true;  
  9.         if (!(o instanceof User)) {  
  10.             return false;  
  11.         }  
  12.         User user = (User) o;  
  13.         return user.name.equals(name) &&  
  14.                 user.age == age &&  
  15.                 user.passport.equals(passport);  
  16.     }  
  17.     //Idea from effective Java : Item 9  
  18.     @Override  
  19.     public int hashCode() {  
  20.         int result = 17;  
  21.         result = 31 * result + name.hashCode();  
  22.         result = 31 * result + age;  
  23.         result = 31 * result + passport.hashCode();  
  24.         return result;  
  25.     }  
  26. }  

2.JDK 7

对于JDK7及更新版本,你可以是使用java.util.Objects 来重写 equals 和 hashCode 方法,代码如下

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import java.util.Objects;  
  2.   
  3. public class User {  
  4.     private String name;  
  5.     private int age;  
  6.     private String passport;  
  7.   
  8.     //getters and setters, constructor  
  9.   
  10.     @Override  
  11.     public boolean equals(Object o) {  
  12.         if (o == thisreturn true;  
  13.         if (!(o instanceof User)) {  
  14.             return false;  
  15.         }  
  16.         User user = (User) o;  
  17.         return age == user.age &&  
  18.                 Objects.equals(name, user.name) &&  
  19.                 Objects.equals(passport, user.passport);  
  20.     }  
  21.   
  22.     @Override  
  23.     public int hashCode() {  
  24.         return Objects.hash(name, age, passport);  
  25.     }  
  26.   
  27. }  

3.Apache Commons Lang

或者,您可以使用Apache Commons LangEqualsBuilder HashCodeBuilder 方法。代码如下
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. import org.apache.commons.lang3.builder;  
  2.   
  3. public class User {  
  4.     private String name;  
  5.     private int age;  
  6.     private String passport;  
  7.     //getters and setters, constructor  
  8.   
  9.      @Override  
  10.     public boolean equals(Object o) {  
  11.   
  12.         if (o == thisreturn true;  
  13.         if (!(o instanceof User)) {  
  14.             return false;  
  15.         }  
  16.         User user = (User) o;  
  17.   
  18.         return new EqualsBuilder()  
  19.                 .append(age, user.age)  
  20.                 .append(name, user.name)  
  21.                 .append(passport, user.passport)  
  22.                 .isEquals();  
  23.     }  
  24.     @Override  
  25.     public int hashCode() {  
  26.         return new HashCodeBuilder(1737)  
  27.                 .append(name)  
  28.                 .append(age)  
  29.                 .append(passport)  
  30.                 .toHashCode();  
  31.     }  
  32. }  

最后测试总结:

在使用上述三种任何一种方式都可以到如下结果:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. User user1 = new User("mkyong"35"111222333");  
  2. User user2 = new User("mkyong"35"111222333");  
  3. System.out.println(user1.equals(user2)); // true</span>  

其实后两种都是对于17和31散列码思想的封装实现。具体请参考《Effective Java》第九条。

整理自:http://blog.csdn.net/jing_bufferfly/article/details/50868266

http://blog.csdn.net/zzg1229059735/article/details/51498310

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值