這篇博客承接上一篇博客,我們來講講重寫equals()
方法時候要滿足的性質——傳遞性
用通俗的話來解釋傳遞性就是說:如果A等於B,然後B等於C,那麼我們就可以說A等於C
以下我們來舉出一個反面例子來幫助理解一下傳遞性的體現
首先我們有一個Point
類該類有橫縱座標的屬性(x
和y
),並且重寫了equals()
方法
package com.blog.effective.note8;
/**
* 〈一個點類〉<br>
*
* @author 未緒
* @time 2017/12/17 11:50
*/
public class Point {
//該點是二位平面上的點
private int x;
private int y;
public Point(int x,int y){
this.x=x;
this.y=y;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Point){
Point p = (Point)obj;
return p.x==this.x&&p.y==this.y;
}
return false;
}
}
以上的代碼可以知道,如果有兩個Point
對象,那麼,只要對應的橫縱座標的數值相等,那麼就可以判斷這兩個點是同一個點。
public static void main(String[] args) {
Point p1=new Point(10,20);
Point p2=new Point(10,20);
System.out.println(p1.equals(p2)); // 輸出 true
}
然後這個時候我們需求增加了,我們要給這個點加上一個Color
屬性,來說明這個點是什麼顏色的。
如果我們不重寫相應的equals()
方法,顯然在比較相等的時候會忽略掉顏色的信息。
如下代碼
package com.blog.effective.note8;
import java.awt.*;
/**
* 〈一個帶有顏色的點〉<br>
*
* @author 未緒
* @time 2017/12/17 11:52
*/
public class ColorPoint extends Point {
//給改點新增加一個顏色元素
private Color color;
public ColorPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ColorPoint) {
ColorPoint cp = (ColorPoint) obj;
return super.equals(obj) && this.color == cp.color; //
}
return false;
}
}
這個時候我們來測試一下我們重寫的equals()
方法
Point point=new Point(1,1);
ColorPoint colorPoint=new ColorPoint(1,1,Color.BLUE);
System.out.println(point.equals(colorPoint)); //true
System.out.println(colorPoint.equals(point)); //false
我們看到輸出得結果就知道這種做法不滿足對稱性。
point.equals(colorPoint)
調用的是Point
類的equals()
方法,由於忽略了顏色信息,所以只要座標相等就會返回 true
colorPoint.equals(point)
調用的是ColorPoint
類的equals()
方法,point
點無顏色信息,所以就會返回false
我們可以嘗試在ColorPoint
類的equals()
方法在進行混合比較的時候忽略顏色的信息
@Override
public boolean equals(Object obj) {
if(obj instanceof ColorPoint){
// 非混合比較
ColorPoint cp = (ColorPoint) obj;
return super.equals(obj) && this.color == cp.color;
}
if (obj instanceof Point) {
//混合比較
return obj.equals(this);
}
return false;
}
這樣的做法滿足了對稱性,但是犧牲了傳遞性,如下測試代碼
ColorPoint cp1=new ColorPoint(1,1, Color.BLUE);
Point p=new Point(1,1);
ColorPoint cp2=new ColorPoint(1,1, Color.RED);
System.out.println(cp1.equals(p)); //true
System.out.println(p.equals(cp2)); //true
System.out.println(cp1.equals(cp2)); //false
cp1.equals(p)
和p.equals(cp2)
的的比較都是忽略顏色信息的,但是cp1.equals(cp2)
之間的比較卻是要考慮顏色信息。
考慮如何解決這樣的一個問題呢?
在equals()
方法中使用getClass()
方法代替instanceof
,將Point
類中的equals()
方法寫爲
@Override
public boolean equals(Object obj) {
if (obj == null || this.getClass() != obj.getClass()) {
return false;
}
Point p = (Point) obj;
return p.x == this.x && p.y == this.y;
}
這樣子的話,就只又對象具有相同的實現的時候,才能使對象相等。但是這樣的結果應該是無法接受的。
還有一種不錯的建議就是——使用複合
我們不再使ColorPoint
繼承Point
,而是在其中加入一個Point
屬性。
public class ColorPoint {
//給改點新增加一個顏色元素
private Color color;
private Point point;
public ColorPoint(int x, int y, Color color) {
point=new Point(x,y);
this.color = color;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ColorPoint) {
ColorPoint cp = (ColorPoint) obj;
return cp.point.equals(obj) && this.color == cp.color;
}
return false;
}
}