复合优先于继承(重写equals方法引出的建议)

博客围绕Java中重写equals方法展开。以Point类和ColorPoint类为例,指出重写equals方法会出现违背对称性和传递性原则的问题。如Point的equals方法忽略颜色判断,修复对称性后又违背传递性。建议不使用继承,将父类包含在子类中,同时重写equals时要重写hashCode。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题复现:
首先有一个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方法时请遵守通用约定”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值