首页 > 解决方案 > 比较 HashSet 中的对象

问题描述

我正在制作一个包含星星的 2D 游戏。我决定在名为 Star 的类中创建构造函数,它给出随机坐标。

public Star(){
    super(0,0);
    x = randomX.nextInt(maxX - minX + 1);
    y = randomY.nextInt(maxX - minY + 1);
}

然后,在其他课程中,我将它们放入 HashSet

Set<Star> star = new HashSet<>();

public Set<Star> generateStars(){
    while (star.size() < numberOfStars){
            star.add(new Star());
    }
    return star;
}

当然,我有 render 和 tick 方法,但我认为不值得粘贴它们。我的讲师告诉我,可以有相同的星星,为了防止我应该使用使用哈希码的身份函数。有人可以帮我弄清楚吗?我想这个函数应该检查哈希码是否相同,如果是这种情况,它应该只返回一个值,这样我们将在 HashSet 中添加 1 个对象而不是 2 个对象。我对吗 ?

标签: javacollections

解决方案


hashCode()在您的类中单独覆盖该方法Star将不起作用,您将不得不覆盖该equals()方法。

请参阅以下代码,其中我们不覆盖该equals()方法:

class Star {
    int x, y;

    public Star(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

public class Main {
    public static void main(String[] args) {
        Star s1 = new Star(0, 0);
        Star s3 = new Star(0, 0);
        Star s2 = new Star(31, -31*31);
        Set<Star> set = new HashSet<>();
        set.add(s1);
        set.add(s2);
        System.out.println(set.size());
    }
}

这将打印 3(而不是您可能期望的 2)。

原因是 add 方法java.util.Set基于equals()方法而不是基于方法比较 2 个对象hashCode()

在上面的Star类代码中,如果添加equals()方法,现在输出将为 2。供您参考,您可以equals()按如下方式覆盖该方法:

@Override
public boolean equals(Object startObject) {
    if (this == startObject) return true;
    if (startObject == null || getClass() != startObject.getClass()) return false;
    Star star = (Star) startObject;
    return x == star.x &&
            y == star.y;
}

那么为什么需要添加hashCode()呢?

  1. 当您HashSet在场景后面使用 add 方法时,将调用该equals()方法并且还将调用hashCode()以决定应该将新对象放入的存储桶。为了保持hashCode()equals()两者的合同应该被覆盖。
  2. 每当您覆盖equals()时,建议也覆盖hashCode()。(反之亦然)。有关详细信息,请参阅链接。

hashCode()and的契约equals():如果对于两个对象说o1and o2o1.equals(o2)那么和的true哈希值是相同的。o1o2 should

确保您正确理解这一点,从上面的陈述中并不暗示如果 2 个对象的哈希值相同,则o1.equals(o2)应该返回true对于 2 个对象,它们的哈希值可能相同,但o1.equals(o2)返回值可能相同false

这里,什么ObjecthashCode()方法保证。

请参阅链接以获取有关此主题的更多详细信息。


推荐阅读