覆盖hashCode()方法

时间:2017-10-16 09:22:08

标签: java oop

Joshua Bloch谈到Effective Java:

  

您必须覆盖覆盖equals()的每个类中的hashCode()。   如果不这样做将导致违反总承包合同   对于Object.hashCode(),它将阻止您的类运行   正确地与所有基于散列的集合一起使用,包括   HashMap,HashSet和Hashtable。

我重写的equals()方法实现了用于比较Match个对象的模糊分数算法:

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.
}

这样这些对象是相同的:

Match match0 = new Match("Man.City", "Atl.Madryt");
Match match1 = new Match("Manchester City", "Atlético Madryt");

我应该如何覆盖hashCode()方法为这些对象生成相同的值?

4 个答案:

答案 0 :(得分:2)

正如M. le Rutte和AxelH已经说过的那样,equals应该只对相同的对象返回true(应该可以随时切换并在代码中呈现相同的结果,无论使用哪个)。

解决此问题的一种方法是使用包装类,在Remove duplicates from a list of objects based on property in Java 8的答案中描述。 你创建它所以包装类只存储计算的模糊值并比较和使用equals和hashcode中的值,然后你可以使用unwrapp来获得实际值。

另一种方法是像yshavit那样做并做另一个类似String的方法:equalsIgnoreCase

答案 1 :(得分:1)

我建议您使用其他方法名称,例如fuzzyEquals而不是equals。您应该根据其使用情况查看hashCodeequals。许多Java类(如HashMap)在未经您同意的情况下调用这两种方法,并要求他们严格遵守他们的想法。他们的想法不是你想要的,而是他们需要的。它是这样的:

  • equals = homeTeam.equals&amp;&amp; awayTeam.equals
  • hashCode = homeTeam.hashCode ^ awayTeam.hashCode

通过重命名,你(a)让HashMap和他的朋友们高兴,(b)避免混淆,(c)提高可读性,(d)有两种不同的方法用于两种不同的事情,你可以单独使用或进一步结合使用。

答案 2 :(得分:1)

要完成,您应该查看数据模型。这是目前失败的那个人

  • Match介于两个Team之间。
  • Team有一个name
  • Teamalias(0..n)。

你会有一些想法:

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
    }
}

然后,只需查看Match以相同的方式使用此类。

班级Team可以提供检查与String匹配的任何别名的方法,如果alias中没有匹配/找到,则会使用name进行检查你的算法。如果此alias匹配,则将其添加到List进行未来研究。

这样,您不需要每次都运行模糊算法。如果您希望用户使Team匹配他选择的任何输入,那么它可能很有用。

答案 3 :(得分:0)

重要的是,match1 == match2然后是match1.hashCode() == match2.hashCode()。假设您有一个数据库,您可以使用id(数字)存储匹配项,然后您可以hashCode返回ID并完成。

不使用数据库来跟踪您可以完成的匹配ID 为每个团队分配一个固定长度的数字ID,并将{id} hashCode的结果连接起来。

例如,"Manchester City"团队可以是团队1"Atlético Madryt"团队2。如果哈希值为32位,那么前16位可以是团队1,最后16位是团队2,如此代表所示。

// 16 bit for team 1 + 16 bit for team 2
0000000000000001        0000000000000010

这是一个有效的32位整数,它将匹配match1 == match2然后match1.hashCode() == match2.hashCode()

的规则