第八条——覆盖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标签保证此点)

        

原文地址:https://www.cnblogs.com/chenfei0801/p/3281037.html