I can't seem to get a HashSet
instance to work as expected. The code I used is as follows:
import testing.Subclass;
import java.util.HashSet;
public class tester {
public static void main(String[] args) throws Exception {
HashSet<Subclass> set = new HashSet<Subclass>();
set.add(new Subclass("007812"));
set.add(new Subclass("007813"));
System.out.println("Set size " + set.size());
set.add(new Subclass("007812"));
System.out.println("Set size " + set.size());
for(Subclass sub : set) {
System.out.println(" sub acctNbr " + sub.getAcctNbr());
}
}
}
Subclass
public class Subclass implements Comparable<Subclass> {
public Subclass(String acctNbr) {
this.acctNbr = acctNbr;
}
private String acctNbr;
public String getAcctNbr() {
return this.acctNbr;
}
public int compareTo(Subclass other) {
return this.getAcctNbr().compareTo(other.getAcctNbr());
}
public boolean equals(Subclass other) {
if(other.getAcctNbr().equals(this.getAcctNbr()))
return true;
else
return false;
}
public int hashCode() {
return acctNbr.hashCode();
}
}
This code outputs
sross@sross-workstation:~/Documents$ javac testing/Subclass.java
sross@sross-workstation:~/Documents$ javac tester.java
sross@sross-workstation:~/Documents$ java tester
Set size 2
Set size 3
sub acctNbr 007812
sub acctNbr 007812
sub acctNbr 007813
sross@sross-workstation:~/Documents$
I had almost the same problem, as everyone said you need to override the right
public boolean equals(Object o)
method. But that's not enough!It is also necessary to override
public int hashCode()
(as you did), otherwise, java wouldn't call theequals
method at all.You did not correctly override
Object.equals()
.The method
boolean equals(Subclass other)
creates a second method which is not what you intended to do.You need to override
equals(Object)
. Instead of doing this you've implemented anequals
method with signatureequals(Subclass)
. Consequently yourHashSet
is using the defaultequals(Object)
method defined onObject
for equality testing.The default
equals(Object)
implementation is based on object identity, and hence the set "allows" you to add twoString
s that, whilst semantically equal, are not the same object.Your equals method is never called. The signature of
equals
requires that it take anObject
, not some other class (including whatever class happens to be implementingequals
).Two meta-points:
First, get in the habit of using
@Override
every time you believe you are overriding a method. That would have caused your example code to fail to compile, leading you to discover the problem.Second, if you're using an IDE, and it didn't highlight a nice bold warning for you, it is misconfigured! You should fix it!
And if you're not using an IDE -- you really, really should be. As soon as you typed
public boolean equals(Subclass other)
, the text would change color and a warning would be displayed telling you what your likely problem is.Incidentally, the standard idiom for
equals()
that I've converged on is this:In some cases, it is worth prepending an
if (object == this) { return true; }
but it's really not worthwhile to make a regular habit of it.First guess, it looks like your
equals(Subclass other)
ought to beequals(Object other)
in order to override thejava.lang.Object.equals()
method, as you want. Probably the set is calling the underlyingequals()
implementation.