问题复现:
首先有一个Point类,重写了equals方法:ide
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类this
public class ColorPoint{ private final Color color; public ColorPoint(int x,int y,Color color){ super(x,y); this.color=color; } }
这时候比较两个点的时候就有个问题:code
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进行比较,忽略了颜色的判断,认定两个类是相等的。
对此咱们作出一些修改:orm
此时可修改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
这样又违背了传递性原则。这时候就有个建议:复合优先于继承
。
即不使用继承方式,而将'父类'包含在'子类'中get
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~hash
参考文献:《Effective Java》第二版 第8条 “覆盖equals方法时请遵照通用约定”io