2

问题复现:
首先有一个Point类,重写了equals方法:

public class Point{
    private final int x;
    private final int y;
    public Point(x,y){
        this.x=x;
        this.y=y;
    }
    @Override public boolean queals(Object o){
        if(!(o instanceof Point){
            return false;
        }
        Point p = (Point)o;
        return p.x == x && p.y == y;
    }
}

另有一个扩展类,ColorPoint继承Point类

public class ColorPoint{
    private final Color color;
    public ColorPoint(int x,int y,Color color){
        super(x,y);
        this.color=color;
    }
}

这时候比较两个点的时候就有个问题:

Point point = new Point(1, 2);
ColorPoint cPoint = new ColorPoint(1, 2, Color.RED);
System.out.println(point.equals(cPoint)); // true
System.out.println(cPoint.equals(point); // false

可以发现equals方法违背了对称性原则,原因是Point的equals方法在接收ColorPoint类型的参数时,会将其当做Point进行比较,忽略了颜色的判断,认定两个类是相等的。
对此我们做出一些修改:

此时可修改equals方法,加入对颜色的判断:
if(!(o.instanceOf(Point))
    return false;
//if o is a normal point,ignore color
if(!(o.instanceOf(ColorPoint))
    return o.equals(this);
//if o is a colorPoint .do a full compation
return super.equals(o) && ((ColorPoint)o).equals(this.color);

这段代码修复了违背对称性的错误,但两个以上的点会有错误,比如 两个ColorPoint和一个Point作比较,如下:

ColorPoint cPointRed = new ColorPoint(1, 2, Color.RED);
Point point = new Point(1, 2);
ColorPoint cPointBlue = new ColorPoint(1, 2, Color.BLUE);
System.out.println(cPointRed.equals(point)); // true
System.out.println(point.equals(cPointBlue)); // true
System.out.println(cPointRed.equals(cPointBlue)); // false

这样又违背了传递性原则。这时候就有个建议:复合优先于继承
即不使用继承方式,而将'父类'包含在'子类'中

public class ColorPoint{
    private final Point point;
    private final Color color;
    public ColorPoint(int x,int y,Color color){
        point.x = x;
        point.x = x
        this.color = color;
    }
    public Point getPoint(){
        return this.point;
    }
    //重写equals
    @Override public boolean equals(Object o){
        if(!(o instanceof ColorPoint){
            return false;
        }
        ColorPoint cp = (ColorPoint)o;
        //只有当坐标和颜色都相同才返回true;
        return cp.point.equals(this.point) && cp.Color.equals(color);
    }
}

当然,重写equals的时候一定记得重写hashCode~重写hashCode~重写hashCode~~de~de~de~

参考文献:《Effective Java》第二版 第8条 “覆盖equals方法时请遵守通用约定”


瓦力
575 声望15 粉丝

一只coder