11

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?

6
  • what is that farAway invocation inside equals?? your class si breaking the contract between hashCode and equals! Commented Jan 24, 2013 at 15:37
  • @AlonsoDominguez There you have a complete test, farAway just return false, to ensure object to be treated as equals, but equals is never called. Commented Jan 24, 2013 at 15:42
  • you must be compliant with contract between hashCode and equals. That means that when your equals method returns true then you hashCode must return the same integer value. And that's not happening in your code. Commented Jan 24, 2013 at 15:44
  • @AlonsoDominguez I understand that, I was trying to avoid hashCode, and use only equals, I see now that is not possible, thanks for insist with contract break, then now I know when equals is not called, I still don't know when does equals is actually called. Commented Jan 24, 2013 at 15:50
  • 1
    @HernánEche: what you seem to be looking to do can be very tricky - not only do you have to adhere to hashCode()'s contract, but also the equals() contract. equals() has to be transitive. So if you return true for A and B because they are close to each other and B and C because they are close to each other, you will run into problems when checking for equality between A and C if they happen to not be close. I think you'll need to devise a container/data structure other than the standard HashSet to do what you want to do (if what you want to do is even a good idea in the first place). Commented Jan 24, 2013 at 19:30

4 Answers 4

32

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.

Sign up to request clarification or add additional context in comments.

11 Comments

I need equals to be called
Then the hashcode shouldn't be the same.
@HernánEche: it makes no sense. HashSet calls equals() to ensure that duplicate objects aren't stored in the set. If it can ensure that without calling equals (for example, because there is nothing in the set yet, or because no other object in the set has the same hash code), why would it call equals()? And with wich other object?
@HernánEche:the two objects return different hashcodes. By the contract for hashCode() the library (or anyone) can take that to mean the objects are not equal - there's never a need to call equals() if the hashcodes are different.
@Hernán: If the hash codes are different, the objects are different and equals is not invoked. If the hash codes are identical, the objects may be equal, hence equals(Object) is called to ensure that they are the same.
|
13

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

6 Comments

Then could you please explain what result you're expecting? What output should your code produce?
Functionality is reject add two objects that are similar, in this case two points in the plane that are close each other, but I can reach same functionality in a hundreds ways, the question is not about solving a single problem, but about to understand when equals is actually called by HashMap, or if equals is never called through it.
I've just tested my code and it works as expected. The call test.add(new Posicion(1,2) returns false because equals() is called. What's wrong with this?
My test was wrong, all clear now, thanks
Are there some drawback using this trick?
|
1

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.

Comments

-1

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; 

}

5 Comments

It is of course not possible to use the farAway method from hashCode(), since you don't have the other object to compare with.
@herman : Hashet works by comparing the object's hashcode. If the hashcode's are different, then there is no need to call equals() because the object's are considered different and both objects will be put in the hashset. equals() is called only if the hashcodes are same and in that case equals() will be called to compare the values
@Zenil no, if hashcodes are same, equals won't be called, just because it means object are the same!, then I still wonder, when does equals is being called?
@herman,@jarnbbjo : faraway() takes 5 arguments. Why do you need the other object to compare with ? You need the other objects' x and y which is passed in. faraway() can be called in hashcode just like it is being called in equals()..Am I missing something ?
@Zenil: Yes, you are missing something. Where do you want to take the arguments other.x and other.y from if you don't have the other object?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.