equals方法实现小记

简介:
    最近做项目,在一次写equals方法时突然悟出了一些心得,小记之,以备后用。在《Effective Java(第二版)》的Item7中提出我们要尽量避免重新equals方法,他同时也列举了几种我们不需要实现equals方法的情况:
1)类的每个实例从本质上来说是唯一的,如Thread类的实例。
2)我们并不会用到该类的equals方法,如Random类,虽然可以比较两个Random的实例,以判断两个实例是否可以产生相同的随机数,设计者认为这样的需求用到的场合很少,因而就没有重写equals方法。
3)父类已经实现了equals方法,并且父类实现方式和子类实现方式是一样的,如大部分的Set实现的equals方法使用AbstractSet类提供的equals方法,List实现则使用AbstractList,Map实现使用AbstractMap的。
4)一个private类或package-private类,我们自己可以确保我们不会使用到它们的equals方法。
同时书也提出一般只有值类型的类才需要实现equals方法,像Date、Integer、Order(作为bean来使用)等。
另外,我们在实现equals方法是也要遵循以下几个原则:
1)自反性(reflexive):x.equals(x)==true
2)对称性(symmetric):x.equals(y)==y.equals(x)
3)传递性(transitive):若x.equals(y)==true, y.equals(z)==true,则x.equals(z)==true。
4)一致性(consistent):多次调用x.equals(y)的结果应该是一样的。
5)对任何非null实例x,x.equals(null)==false。

根据这些特性,我们可以写出如下代码:
 1  public   class  Customer  implements  Serializable {
 2       private   static   final   long  serialVersionUID  =   1L ;
 3      
 4       private  String id;
 5       private  String name;
 6       private  String role;
 7      
 8      @Override
 9       public   boolean  equals(Object obj) {
10           if (obj  ==   null ) {
11               return   false ;
12          }
13          
14           if ( this   ==  obj) {
15               return   true ;
16          }
17          
18           if (!(obj  instanceof  Customer)) {
19               return   false ;
20          }
21          
22          Customer other  =  (Customer)obj;
23           return  (ObjectUtils.equals(id, other.id)  &&  
24                  ObjectUtils.equals(name, other.name)  &&
25                  ObjectUtils.equals(role, other.role));
26      }
27      
28       public  String getId() {
29           return  id;
30      }
31       public   void  setId(String id) {
32           this .id  =  id;
33      }
34       public  String getName() {
35           return  name;
36      }
37       public   void  setName(String name) {
38           this .name  =  name;
39      }
40       public  String getRole() {
41           return  role;
42      }
43       public   void  setRole(String role) {
44           this .role  =  role;
45      }
46  }
其中ObjectUtils类的代码如下:
 1  public   class  ObjectUtils {
 2      
 3       /**
 4       * Compare whether the left and right is equals
 5       * It has already considered the null case
 6       * 
 7       *  @param  left
 8       *  @param  right
 9       *  @return
10        */
11       public   static   boolean  equals(Object left, Object right) {
12           if (left  ==   null   &&  right  ==   null ) {
13               return   true ;
14          }
15           if (left  ==   null   &&  right  !=   null ) {
16               return   false ;
17          }
18           return  left.equals(right);
19      }
20  }
在《Effective Java》这本书中,貌似equals实现方法前面没有null、this的判断,因为instanceof可以解决null的问题,而super.equals()方法可以解决this问题,但是我还是喜欢把它们都分出来,这样写的更加明了一些。另外,事实上,这里的实现并没有遵循对称性的原则,因为如果A是B的子类,而这个equals方法在A类中,那么AInstance.equals(BInstance)==false,若B也实现了类似的equals方法,则BInstance.equals(AInstance)==true(当A没有新的比较字段时,或许这个时候A根本就不需要实现equals方法,如本文开头列出的第三条),这是因为AInstance instanceof BInstance == true,反之则为false。不过由于这种情况并不常见,所以就不去care了。:)

    事实上,这里我之所以要记录这些代码,主要是因为有ObjectUtils类的存在。记得以前在学C#的时候,它的Object类提供了一个静态的Equals方法,我一直对这个方法的存在感到很疑问,直到这次自己写这个equals方法才弄明白,因为虽然在equals方法实现中,最后还要判断类字段是否equals,然后这些字段都有可能是null的,如果没有提供这个静态的equals方法,我们就需要自己来判断每个字段是否为null,然后才可以调用它的equals方法,这样就比较麻烦了,而Object.Equals方法正是对这种行为的封装,我们只要使用一个方法就可以安全的实现类成员的equals。这也是我加ObjectUtils类的意义所在。希望以后能有机会向这个ObjectUtils类填充更多的实用方法。:)

PS:如一楼所说在commons中的 EqualsBuilder已经实现了相同的功能,而且代码更加完善,有兴趣的可以看看那里的代码,我这里只是对这次新的的记录,代码只是对当前我考虑的场景中使用,并没有考虑其他方面。另外,在《Effective Java》中也是建议equals和hashCode两个方法应该是同时实现的,一楼也有说可以用HashCodeBuider来实现,这个大家也不妨可以去看看里面的源码,最近时间不多,以后回来再看。。。。。。

相关文章
|
存储 Java 程序员
equals方法深入解析
equals方法深入解析
250 0
|
2月前
|
存储 Java
两个对象的 hashCode()相同,则 equals()
当两个对象的 `hashCode()` 方法返回值相同时,这两个对象的 `equals()` 方法不一定返回 `true`。`hashCode()` 相同仅表示两对象可能相等,需进一步通过 `equals()` 方法验证对象是否真正相等。
34 7
|
6月前
|
Java 容器
equals与hashcode的区别与联系
equals与hashcode的区别与联系
|
8月前
|
存储 Java 对象存储
当hashCode相同时,equals是否也相同?
当hashCode相同时,equals是否也相同?
48 0
|
存储 Java
“==”和equals 最大的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储 Java
详解“==”和equals的区别
“==”和equals 最大的区别是 “==”是运算符,如果是基本数据类型,则比较存储的值;如果是引用数据类型,则比较所指向对象的地址值。 equals是Object的方法,比较的是所指向的对象的地址值,一般情况下,重写之后比较的是对象的值。
|
存储
"=="和 equals 方法究竟有什么区别?
"=="和 equals 方法究竟有什么区别?
138 0
|
存储 NoSQL
简单讲一下 HashCode() 与 equals()方法
简单讲一下 HashCode() 与 equals()方法.
118 0
|
存储 缓存 算法
关于 equals 和 hashCode,看这一篇真的够了!
这几天在尝试手撸一个类似Lombok的注解式代码生成工具,用过Lombok的小伙伴知道,Lombok可以通过注解自动帮我们生产equals()和hashCode()方法,因此我也想实现这个功能,但是随着工作的深入,我发现其实自己对于equals()和hashCode()的理解,也处在一个很低级的阶段。
关于 equals 和 hashCode,看这一篇真的够了!
|
存储 算法 Java
equals 和 hashCode 到底有什么联系?
写在前面 Java的基类Object提供了一些方法,其中equals()方法用于判断两个对象是否相等,hashCode()方法用于计算对象的哈希码。equals()和hashCode()都不是final方法,都可以被重写(overwrite)。
equals 和 hashCode 到底有什么联系?