HashSet实现了hashCode()和equals()方法但仍然会添加重复的条目。

9

I have the following class:

class Point
{
     double x, y;

     // .... constructor and other functions here

     public boolean equals(Point p)
     {
         if(p==null) return(false);
         return(x==p.x && y==p.y);
     }

    public int hashCode()
    {
        int result=17;

        long c1=Double.doubleToLongBits(x);
        long c2=Double.doubleToLongBits(y);

        int ci1=(int)(c1 ^ (c1 >>> 32));
        int ci2=(int)(c2 ^ (c2 >>> 32));

        result = 31 * result + ci1;
        result = 31 * result + ci2;

        return result;
    }
}

现在,如果我写下以下代码:
    Point x=new Point(11,7);
    Point y=new Point(11,7);

    System.out.println("hash-code of x=" + x.hashCode());
    System.out.println("hash-code of y=" + y.hashCode());
    System.out.println("x.equals(y) = " + x.equals(y));
    System.out.println("x==y = " + (x==y));

    java.util.HashSet<Point> s=new java.util.HashSet<Point>();
    s.add(x);
    System.out.println("Contains "+y.toString()+" = "+s.contains(y));
    s.add(y);
    System.out.println("Set size: "+s.size());
    java.util.Iterator<Point> itr=s.iterator();
    while(itr.hasNext()) System.out.println(itr.next().toString());

我得到了下面的输出:
hash-code of x=79052753
hash-code of y=79052753
x.equals(y) = true
x==y = false
Contains (11.0,7.0) = false
Set size: 2
(11.0,7.0)
(11.0,7.0)

请帮助我理解为什么`contains()`返回false(即使`equals()`和`hashCode()`返回相同的值),以及如何纠正这个问题(即防止Java添加重复元素)。谢谢。

2
哇!如果所有问题都如此清晰易懂,并且具有可复现的代码和输出,那将是非常棒的。干得好! - Seelenvirtuose
2个回答

8

你已经修改了方法签名,从 Object.equals(Object),所以你并没有正确的重写 equals。我建议你使用 @Override 注解来捕获这类错误。你的方法应该是这样的,

@Override
public boolean equals(Object o)
{
     if (this == o) {
         return true;
     }
     if (o instanceof Point) {
         Point p = (Point) o;
         return(x==p.x && y==p.y);
     }
     return false;
}

我已经修改了我的代码并正确覆盖了它,这解决了我的问题。非常感谢。 - user1637645

7

你没有覆盖Object类中的equals方法。

equals方法的签名为:

public boolean equals(Object obj)

而不是

public boolean equals(Point obj)

请不要使用==来比较双精度浮点数。应该使用Double.equals。


1
简单类型的值可以使用 == 进行比较。 - Sergey Morozov
2
@SergeyMorozov - 不行。在浮点数比较中使用“==”是不推荐的,这是不安全的。 - MS Srikkanth
谢谢,它解决了我的问题。就比较而言,根据文档,当比较-0.0和+0.0时,Double.equals返回false;因此我认为我会坚持使用==而不是Double.equals()。 - user1637645
@user3493289 对于更强大的实现,我们必须使用+/- delta差异,即abs(x1-x2)<=delta,这是在检查实数时我们能希望的最好结果。 - user1637645
3
尽管我一般赞同谨慎使用浮点数比较和 ==,但是基于差值的比较不能用于实现 equals 方法:equals 方法必须是传递性的。考虑(仅用于说明问题)x=1y=2z=3 的值。使用1.5的差值,你会有 x.equals(y)y.equals(z),但是 x.equals(z)不成立。这违反了 equals 的约定。 - Marco13
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接