Reputation: 537
I have a class like this:
class Vertex {
char v;
char w;
int cost;
public Vertex(char v, char w, int cost){
this.v = v;
this.w = w;
this.cost = cost;
}
@Override
public String toString(){
return "["+v+" "+w+" "+cost+"]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Vertex vertex = (Vertex) o;
return (v == vertex.v && w == vertex.w) || (w == vertex.v && v == vertex.w);
}
@Override
public int hashCode() {
return Objects.hash(v, w);
}
}
I am trying to have the equals()
return true when two vertexes are equal or opposite equal. Meaning it should return true if there is a vertex (v,w) and (w,v).
My equals()
is symmetric and reflexive as it should be, but still the set.contains()
return false for (v,w) and (w,v) case.
I would appreciate any help.
Upvotes: 1
Views: 430
Reputation: 272760
Your class violates the general contract for hashCode()
, not equals()
. Set.contains()
uses hashCode()
to achieve O(1) time.
The general contract for hashCode()
states that equal objects must have equal hash codes. However, in your case, [v=1, w=2]
and [v=2, w=1]
are considered equal, but they have different hash codes. You'd be calling Objects.hash(1, 2)
and Objects.hash(2, 1)
respectively.
You should change your hash code implementation to make it independent of the order of v
and w
. One way to do this is to hash the smaller one first:
return Objects.hash(Math.min(v, w), Math.max(v, w));
Upvotes: 1
Reputation: 58812
As @Sweeper wrote, your hashCode should return same value in any parameters order, so you can return sum of parameters' hashCode:
@Override
public int hashCode() {
return Objects.hashCode(v) + Objects.hashCode(w);
}
Upvotes: 1