在Map键比较中使用的Equals方法



我知道这是不可能扩展一个类,它覆盖方法equals(),并保持它"保留"当有人在子类中添加一个新的方面。Point类及其子类的常见示例演示了它:

public class Point {
    Double d1;
    Double d2;
    public Point(double d1, double d2){
        this.d1 = d1;
        this.d2 = d2;
    }
}
public class ColorPoint extends Point {
    String color;
    public ColorPoint(double d1, double d2, String s) {
        super(d1, d2);
        color = s;
    }
}

如果我们让Eclipse创建方法equals()hashCode(),它也会考虑ColorPoint的颜色属性。因此证明了equals()方法是不对称的。代码:

Point p1 = new Point(2,2);
ColorPoint cp1 = new ColorPoint(2, 2, "blue");
System.out.println(p1.equals(cp1));
System.out.println(cp1.equals(p1));

打印:

真的假

用同样的方法可以证明该方法是不可传递的。但是,当我在HasMap中将对象作为键传递时,无论我传递它们的顺序如何,它都会将它们识别为不同的。代码:

Point p1 = new Point(2,2);
Point p2 = new Point(3.1,3.1);
ColorPoint cp1 = new ColorPoint(2, 2, "blue");
ColorPoint cp2 = new ColorPoint(3.1,3.1, "red");

Map<Point, Integer> map = new HashMap<>();
map.put(cp2, 4); map.put(cp1, 3);
map.put(p1, 1); map.put(p2, 2); 
System.out.println(map.size());

总是打印4,即使我以另一种顺序传递对象。这在意料之中吗?那么,Map使用哪种方法来比较键呢?

这可能是因为eclipse生成的hashcode()考虑了colorpoint的颜色字段,所以points和colorpoint散列到不同的bucket中,并且永远不会与equals()进行比较。

请注意,这意味着hashcode()的契约被破坏了——a.equals(b) == true的两个对象产生了不同的哈希码。基本上,不要这样做!

Scala语言对此有一个有趣的理解,使用canEqual方法来确定两个对象是否可以相等。点击这里查看

最新更新