问题
I executed below code and found the output was false
.
import java.util.Set;
import java.util.HashSet;
public class Name {
private String first, last;
public Name(String first, String last) {
this.first = first;
this.last = last;
}
public boolean equals(Object o) {
if (!(o instanceof Name))
return false;
Name n = (Name) o;
return n.first.equals(first) && n.last.equals(last);
}
public static void main(String[] args) {
Set<Name> s = new HashSet<Name>();
s.add(new Name("Donald", "Duck"));
System.out.println(s.contains(new Name("Donald", "Duck")));
}
}
I want to know how it behaves and why output is false
.
回答1:
You need to override hashCode()
method also along with equals()
. Both the methods are used for proper functionality of HashSet
, so must be overriden in a user-defined class if you are making that class
as a key
, else hashCode()
of Object
class is getting used and no two different objects
can be considered as same as their hashCode()
would always be different, and will for sure return false
always in the case of contains()
.
回答2:
In order for a HashSet
(or HashMap
, for that matter) to properly locate your object, you need to override the hashCode()
method so that two object which are equal have the same hashCode. The canonical way of doing this looks like this (assuming first
and last
can't be null
, like your equals
method assumes:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + first.hashCode();
result = prime * result + last.hashCode();
}
回答3:
Any Hash
based data structure implementation (collection) in Java checks duplication based on two things :
1 : if equals
method returns true
for any of elements which are already stored in collection.
2 : if the hashCode
method returns the same integer value
for any of elements which are already stored in collection.
So in your case you haven't overridden the hashCode method, it means it will try to check hashCode equality using hashCode method default implementation of Object
class which is not aware of your last
and first
variables.
I hope it helps.
回答4:
Your equals()
method is ok, but you have missed to override hashCode()
method, just override the hashCode()
method, it will work. And don't forgot you always need to override both equals() and hashCode()
or none of them to get the correct behavior. If you are planing to use your objects as a key in hashing mechanism than you must override both of them.
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((first == null) ? 0 : first.hashCode());
result = prime * result + ((last == null) ? 0 : last.hashCode());
return result;
}
回答5:
You must override hashCode()
in every class that overrides equals()
. Failure to do so will result in a violation of the general contract for Object.hashCode()
, which will prevent your class from functioning properly in conjunction with all hash-based collections, including HashMap, HashSet, and Hashtable
.
from Effective Java, by Joshua Bloch
回答6:
You can also see how your code will be executed.
When you try to add element in set it calls the hash code and it gets bucket.
Once you get the hash value from hash code the overrided equals will be run for all those who are having same hash token.
Hope this helps.
来源:https://stackoverflow.com/questions/31470515/hashset-contains-method