• 第八条——覆盖equals方法时需遵守的通用约定


    1)自反性  

              对于任何非null的引用值x,x.equals(x)必须返回true。---这一点基本上不会有啥问题

    2)对称性

              对于任何非null的引用值x和y,当且仅当x.equals(y)为true时,y.equals(x)也为true。

            JDK中就有这样的错误。如java.sql.Timestamp对java.util.Date进行了扩展,并且增加了nanoseconds域。Timestamp的equals方法就违反了对称性。

            下面我们来分析下这个方法

             

    //Date.java
     public boolean equals(Object obj) {
            return obj instanceof Date && getTime() == ((Date) obj).getTime();
        }
    
    
    
    //Timestamp.java
        public boolean equals(java.lang.Object ts) {
          if (ts instanceof Timestamp) {
    	return this.equals((Timestamp)ts);
          } else {
    	return false;
          }
        }
    
      public boolean equals(Timestamp ts) {
    	if (super.equals(ts)) {
    	    if  (nanos == ts.nanos) {
    		return true;
    	    } else {
    		return false;
    	    }
    	} else {
    	    return false;
    	}
        }
    

      比如说Date d ; Timestamp t.那么d.equals(t)==true,但是从Timestamp的equals方法可以看到,t.equals(d)==false

    3)传递性 

             对于任何非null的引用值x、y、z。如果x.equals(y)==true,y.equals(z)==true,那么x.equals(z)==true。

              这一条主要是针对子类增加了新的属性导致的.

             我们可以再一个抽象的类的子类中增加新的属性,而不会违反equals约定。只要不能直接创建超类的实例,上述几种约定的问题就不会出现。

    4) 一致性 

            对于任何非null的引用值x和y,只要equals的比较操作在对象所用的信息没有被修改,那么多次调用x.eqals(y)就会一致性地返回true,或者一致性的返回false。

    5)非空性

          所有比较的对象都不能为空。

          许多类的equals方法都通过一个显示的null测试来防止这种现象,如下所示:

           

    @override
    public boolean equals(Object o) {
             if(o==null) {
                   return false;
                      }
            .........
    }

    其实没有必要,因为为了测试equals参数的等同性,equals方法必须先把参数转换成适当的类型,以便可以调用它的访问方法,或者域。在进行转换前,equals方法必须使用instanceof操作符,检查其参数是否为正确的类型,如下所示:

    @override
    public boolean equals(Object o) {
             if(!(o instanceof MyType)) {//如果o==null,这一步就返回false
                   return false;
                      }
            .........
    }

    综上所述,得出 以下实现高质量equals方法的诀窍

    1. 使用==操作符检查“参数是否为这个对象的引用”。。这只不过是一种性能优化,如果比较操作可能跟昂贵,就值得这么做。

    2. 使用instanceof操作符检查“参数是否为正确的类型”

    3. 把参数转换成正确的类型

    4. 对于该类的每个“关键”域,检查参数中的域是否与该对象中对应的域匹配。 

         注意域的比较顺序可能会影响equals方法的性能,为了获得最佳的性能,应该最先比较最不可能一致的域或者开销最小的域。

    5. 当完成equals方法时,一定要检查是否符合:对称性、传递性、一致性

    6. 覆盖equals方式时总是要覆盖hashCode方法

    7. 不要企图让equals方法过于智能

    8.不要把equals方法声明中的参数Object类型替换为其他类型(用@override标签保证此点)

            

  • 相关阅读:
    Android系统的Binder机制之一——Service Manager
    Android系统的Binder机制之二——服务代理对象(1)
    电子书
    [ 具体数学 ] 1:递归式与封闭式
    线段树封装
    实验1——顺序表的合并
    配置终端VIM 文件
    编译原理:实验二、集合与线性表操作
    括号匹配检验
    Problem B: KMP算法综合应用余庆
  • 原文地址:https://www.cnblogs.com/chenfei0801/p/3281037.html
Copyright © 2020-2023  润新知