Joshua Bloch says on Effective Java:
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.
My overridden equals()
method implements fuzzy score algorithm for comparing Match
objects:
public class Match {
private String homeTeam;
private String awayTeam;
public Match(String homeTeam, String awayTeam) {
this.homeTeam = formatTeamName(homeTeam);
this.awayTeam = formatTeamName(awayTeam);
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Match that = (Match) o;
final int threshold = 6;
return (computeFuzzyScore(this.homeTeam, that.awayTeam) <= threshold || computeFuzzyScore(this.awayTeam, that.homeTeam) <= threshold) &&
computeFuzzyScore(this.homeTeam, that.homeTeam) > threshold && computeFuzzyScore(this.awayTeam, that.awayTeam) > threshold;
}
// formatTeamName(), computeFuzzyScore() have been left out for brevity.
}
This way these objects are equal:
Match match0 = new Match("Man.City", "Atl.Madryt");
Match match1 = new Match("Manchester City", "Atlético Madryt");
How should I override hashCode()
method to generate same value for such objects?
As the answers by M. le Rutte and AxelH already say, equals should only return true for objects that are the same (should be okay to switch between at all times and render the same results in your code regardless of which is used).
One way to solve this is to use a wrapper-class, described in the answer to Remove duplicates from a list of objects based on property in Java 8 . You make it so the wrapper class only stores the computed fuzzy values and compare and uses the values in both the equals and the hashcode, then you may use unwrapp to get the real values.
Another way is to do like yshavit said and do another equal similar to String:equalsIgnoreCase
I would recommend you use some other method name such as fuzzyEquals
instead of equals
. You should view hashCode
and equals
in terms of their usage. Many Java classes such as HashMap
call these two methods without your consent and require them to adhere strictly to their idea. And their idea is not what you want, but what they need. It's something like this:
By renaming, you (a) keep HashMap and his friends happy, (b) avoid confusion, (c) improve readability and (d) have two different methods for two different things, which you can use independently or combine further.
To be complete, you should review the data model. It is the one failing you for the moment
Match
is between two Team
. Team
have a name
Team
have alias
(0..n). You would have somethink like :
public Team{
private final String name;
private List<String> alias;
public Team(Sting name){ ... }
public boolean equals(Object obj){
// check name
}
public int hashCode(){
// hash the name
}
}
Then, just review the Match
to used this class the same way.
The class Team
could provide a method to check for any alias matching a String
, if not matching/found in alias
, it would check with the name
using your algo. If this alias
match, you add it to the List
for futur research.
That way, you don't need to run your fuzzy algorithm each time. It could be usefull if you want a user to get the Team
matching any input of his choice.
The important part is that if match1 == match2
then match1.hashCode() == match2.hashCode()
. Let's say that you have a database where you store the match with an id (a number) then you can have hashCode
return the id and be done.
without using a database to keep track of the id of matches you could be done with assigning every team a numeric id of fixed length and concatenate the two id as a result of hashCode
.
As an example the "Manchester City"
team could be team 1
and "Atlético Madryt"
team 2
. If the hash is 32 bit long you can have the first 16 bit be the team 1
and the last 16 be team 2
as in this representation.
// 16 bit for team 1 + 16 bit for team 2
0000000000000001 0000000000000010
An this is a valid 32 bit integer that will match the rule of match1 == match2
then match1.hashCode() == match2.hashCode()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.