I don't usually code in Java, but recently I started not having a choice. I might have some major misunderstanding of how to properly use HashSet. So it might be possible something I did is just plain wrong. However I'm grateful for any help, you might offer. So the actual problem:
In a small program I was writing, I was generating very similar objects, which, when created, would have a very specific id (a string
or in my last iteration a long
). Because each object would spawn new objects, I wanted to filter out all those I already created. So I started throwing the id of every new object into my Hash(Set) and testing with HashSet.contains()
, if an object was created before. Here is the complete code:
// hashtest.java
import java.util.HashSet;
class L {
public long l;
public L(long l) {
this.l = l;
}
public int hashCode() {
return (int)this.l;
}
public boolean equals(L other) {
return (int)this.l == (int)other.l;
}
}
class hashtest {
public static void main(String args[]) {
HashSet<L> hash = new HashSet<L>();
L a = new L(2);
L b = new L(2);
hash.add(a);
System.out.println(hash.contains(a));
System.out.println(hash.contains(b));
System.out.println(a.equals(b));
System.out.println(a.hashCode() == b.hashCode());
}
}
produces following output:
true
false
true
true
so apparently, contains
does not use the equals
function provided by L
, or I have some major misunderstanding of the concept ...
I tested it with openjdk (current version included in ubuntu) and the official current java from Oracle on Win7
for completeness official java-api documentation for HashSet.contains()
:
public boolean contains(Object o)
Returns
true
if this set contains the specified element. More formally, returnstrue
if and only if this set contains an elemente
such that(o==null ? e==null : o.equals(e))
.
http://download.oracle.com/javase/6/docs/api/java/util/HashSet.html#contains(java.lang.Object)
Any ideas or suggestions?
Your equals
method needs to take an Object
.
Because you declared it as taking an L
, it becomes an additional overload instead of overriding the method.
Therefore, when the hashSet
class calls equals
, it resolves to the base Object.equals
method. When you call equals
, you call your overload because a
and b
are both declared as L
instead of Object
.
To prevent this issue in the future, you should add @Override
whenever you override a method.
This way, the compiler will warn you if it isn't actually an override.