不覆盖equals方法,在这种情况下,类的每个实例都只与它自身相等,如果满足了一下任何一个条件,这就正是所期望的结果
类的每个实例本质上都是唯一的
不关心类是否提供了“逻辑相等”的测试功能
超类已经覆盖了equals,从超类继承过来的行为对于子类也是合适的。
类是私有的或是包级私有的,可以确定他的equals方法永远不会被调用。这时,应该覆盖equals方法,以防它被意外调用
@override public boolean equals(Object o){
throw new AssertionError();//Mehtod is never called
}

如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时就需要覆盖equals方法。
这通常属于“值类”的情形。有一种”值类“不需要覆盖equals方法,即用实例受控确保“每个值至多只存在一个对象”的类。
对于这样的类,逻辑相同与对象等同是一回事。因此Object的equals方法等同于逻辑意义上的equals方法 枚举就属于这种类

在覆盖equals方法时,必须遵守下面的约定:
equals方法实现了等价关系:
1:自反性 对于任何非null的引用值x,x.equals(x)必须返回true
2:对称性
3:传递性
4:一致性 未修改对象的情况下,多次调用返回结果一样
对于任何非null的引用值x,x.equals(null)必须返回false

*/

class Point{
private final int x;
private final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
@Override public boolean equals(Object o){
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == this.x && p.y == this.y;
}
//Remainder omitted
}
//假设需要扩展这个类,为一个点添加颜色信息:
class ColorPoint extends Point{
private final Color color;
public ColorPoint(int x, int y, Color color){
super(x,y);
this.color = color;
}
// @Override
// public boolean equals(Object o) {//这样会失去对称性
// if (!(o instanceof ColorPoint))
// return false;
// return super.equals(o) && ((ColorPoint)o).color == color;
// }
//Point p = new Point(1,2);
//ColorPoint cp = new ColorPoint(1,2,Color.RED);
//p.equals(cp); true cp.equals(p); false
@Override
public boolean equals(Object o) {//这样会失去传递性
if (!(o instanceof Point))
return false;
if (!(o instanceof ColorPoint))
return false;
return super.equals(o) && ((ColorPoint)o).color == color;
}
//ColorPoint p1 = new ColorPoint(1,2,Color.RED);
//Point p2 = new Point(1,2);
//ColorPoint p3 = new ColorPoint(1,2,Color.BLUE);
//p1.equals(p2); true p2.equals(p3); true p1.equals(p3) false
//Remainder omitted
}
//上面例子结论:我门无法在扩展可实例化的类的同时,既增加新的值组件,同时又保留equals约定,除非愿意放弃面向对象的抽象所带来的优势
//里氏替换原则认为,一个类型的任何重要属性也将适用于他的子类型,因为该类型编写的任何方法,在它的子类型上也应该同样运行的很好
//虽然没有一种令人满意的方法既可以扩展可实例化类,又增加组件,但还是有一种不错的权宜之计。根据第16条建议:复合优先于继承。
//我们不再让ColorPoint扩展Point,而是在ColorPoint中加入一个私有的Point域,以及一个共有的视图方法,
// 此方法返回一个于该有色点处在相同位置的普通Point对象
class ColorPoint_Change{
private final Point point;
private final Color color;
public ColorPoint_Change(int x, int y, Color color){
if (color == null)
throw new NullPointerException();
point = new Point(x, y);
this.color = color;
}

/*
returns the point-view of this color point
*/
public Point asPoint(){
return point;
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof ColorPoint_Change))
return false;
ColorPoint_Change cp = (ColorPoint_Change)obj;
return cp.point.equals(point) && cp.color.equals(color);
}
}
//注意:可以在一个抽象类的子类中增加新的值组件,而不会违反equals约定
//域的比较顺序可能会影响到equals方法的性能。为了获得最佳的性能,应该最先比较最有可能不一致的域,或者开销最低的域,
// 最理想的情况是两个条件同时满足的域。
//覆盖equals方法时总要覆盖hashCode
//不要企图让equals方法过于智能
//不要将equals声明中的Object对象替换为其他的类型,@Override注解的用法可以防止犯这种错误
posted on 2017-10-11 15:36  飞奔的菜鸟  阅读(180)  评论(0)    收藏  举报