When does HashSet 'add' method calls equal

2020-01-24 05:48发布

问题:

I did this test in a HashSet comparision and equals is not being called

I would like to consider equals when farAway=false (A function to check two point distances)

Full compilable code, you could test it, and tells why equals is not being called in this example.

public class TestClass{
     static class Posicion
    {
        private int x;
        private int y;

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Posicion other = (Posicion) obj;
            if ( farAway(this.x, other.x, this.y, other.y,5)){   
                return false;
            } 
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7; hash = 59 * hash + this.x; hash = 59 * hash + this.y;
            return hash;
        }

         Posicion(int x0, int y0) {
            x=x0;
            y=y0;
        }

        private boolean farAway(int x, int x0, int y, int y0, int i) {
            return false;
        }
    }

    public static void main(String[] args) {
        HashSet<Posicion> test=new HashSet<>();
        System.out.println("result:"+test.add(new Posicion(1,1)));
        System.out.println("result:"+test.add(new Posicion(1,2)));
    }
}

EDIT

-Is there a way to force HashSet add to call equals?

回答1:

If the hash codes differ, there is no need to call equals() since it is guaranteed to return false.

This follows from the general contract on equals() and hashCode():

If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

Right now your class is breaking that contract. You need to fix that.



回答2:

If you want equals() to be called always, just always return, say, 0 in hashCode(). This way all items have the same hash code and are compared purely with equals().

public int hashCode() {
  return 0;
}


回答3:

It sounds like HashSet isn't right for you. It sounds like you want a custom way of comparing two positions. Rather than saying "are two positions exactly equal?". Instead, you should look at using TreeSet, with a Comparator. This way, you can write a "IsWithinRangeComparator" and do your range checking there.



回答4:

As suggested above,when objects are equal, their hashcode should also be the same. You could make a simple fix to your hashcode computation like below.

 public int hashCode() {

int hash = 7; hash = 59 * hash + this.x; hash = 59 * hash + this.y;
boolean faraway=farAway(this.x, other.x, this.y, other.y,5);
hash=59*hash+(faraway?1:0); //include faraway also as part of hashcode computation

 return hash;

}