不覆盖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注解的用法可以防止犯这种错误