然而,对比redP和blueP的结果是false:

System.out.println(redP.equals(blueP)); // 打印 false

  因此,equals的传递性被违背了。

  使equals的关系更一般化似乎会将我们带入到死胡同。我们应该采用更严格化的方法。一种更严格化的equals方法是认为不同类的对象是不同的。这个可以通过修改Point类和ColoredPoint类的equals方法来达到。你能增加额外的比较来检查是否运行态的这个Point类和那个Point类是同一个类,像如下所示的代码一样:

// A technically valid, but unsatisfying, equals method
public class Point {

    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override public boolean equals(Object other) {
        boolean result = false;
        if (other instanceof Point) {
            Point that = (Point) other;
            result = (this.getX() == that.getX() && this.getY() == that.getY()
                    && this.getClass().equals(that.getClass()));
        }
        return result;
    }

    @Override public int hashCode() {
        return (41 * (41 + getX()) + getY());
    }
}

  你现在可以将ColoredPoint类的equals实现用回刚才那个不满足对称性要的equals实现了。

public class ColoredPoint extends Point { // 不再违反对称性需求

    private final Color color;

    public ColoredPoint(int x, int y, Color color) {
        super(x, y);
        this.color = color;
    }

    @Override public boolean equals(Object other) {
        boolean result = false;
        if (other instanceof ColoredPoint) {
            ColoredPoint that = (ColoredPoint) other;
            result = (this.color.equals(that.color) && super.equals(that));
        }
        return result;
    }
}

  这里,Point类的实例只有当和另外一个对象是同样类,并且有同样的坐标时候,他们才被认为是相等的,即意味着 .getClass()返回的是同样的值。这个新定义的等价关系满足了对称性和传递性因为对于比较对象是不同的类时结果总是false。所以着色点(colored point)永远不会等于点(point)。通常这看起来非常合理,但是这里也存在着另外一种争论——这样的比较过于严格了。

  考虑我们如下这种稍微的迂回的方式来定义我们的坐标点(1,2)

Point pAnon = new Point(1, 1) {
    @Override public int getY() {
        return 2;
    }
};

  pAnon等于p吗?答案是假,因为p和pAnon的java.lang.Class对象不同。p是Point,而pAnon是Point的一个匿名派生类。但是,非常清晰的是pAnon的确是在坐标1,2上的另外一个点。所以将他们认为是不同的点是没有理由的。