Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HashSet adds duplicate entries despite implementing both hashCode() and equals()

Tags:

java

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;
    }
}

Now, if I write the following code:

    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());

I am getting the following output:

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)

Please help me in understanding why contains() returns false (even after equals() and hashCode() return the same value) and how can I rectify this (i.e. preventing Java from adding duplicate elements). Thanks in advance.

like image 819
user1637645 Avatar asked Apr 23 '16 05:04

user1637645


People also ask

Does HashSet add duplicate values?

Duplicates: HashSet doesn't allow duplicate values. HashMap stores key, value pairs and it does not allow duplicate keys. If the key is duplicate then the old key is replaced with the new value.

Why does my HashSet contain duplicates?

The problem is that your Element class has not overridden the equals and hashCode methods or these implementations are broken. It is reflexive: for any non-null reference value x, x. equals(x) should return true.

How can you avoid adding duplicate items to a set?

For a hashed collection you need to implement equals()/hashCode() appropriately for Employee, and then a HashSet will guarantee you don't have any duplicates... Also: you don't need to check if the set contains the element first. Just call add , and if the element already exists in the set, it won't be added again.


2 Answers

You have changed the method signature from Object.equals(Object), so you aren't correctly overriding equals. I suggest you use the @Override annotation to catch this class of bugs. Your method should look something like,

@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;
}
like image 102
Elliott Frisch Avatar answered Nov 02 '22 23:11

Elliott Frisch


You are not overriding the equals method in Object.

The signature of equals method is:

public boolean equals(Object obj)

and not

public boolean equals(Point obj)

And please do not compare double values using ==. You should use Double.equals instead.

like image 21
MS Srikkanth Avatar answered Nov 03 '22 00:11

MS Srikkanth