我正在制作一款有星星的 2D 游戏。我决定在名为 Star 的类中创建给出随机坐标的构造函数。
public Star(){
super(0,0);
x = randomX.nextInt(maxX - minX + 1);
y = randomY.nextInt(maxX - minY + 1);
}
Run Code Online (Sandbox Code Playgroud)
然后,在其他课程中我将它们放入 HashSet 中
Set<Star> star = new HashSet<>();
public Set<Star> generateStars(){
while (star.size() < numberOfStars){
star.add(new Star());
}
return star;
}
Run Code Online (Sandbox Code Playgroud)
当然,我有渲染和勾选方法,但我认为不值得粘贴它们。我的讲师告诉我,可以有相同的星星,为了防止我应该使用使用哈希码的身份函数。有人可以帮我解决这个问题吗?我想这个函数应该检查哈希码是否相同,如果是这样,它应该只返回一个值,这样我们就可以将 1 个对象而不是 2 个对象添加到 HashSet 中。我对吗 ?
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());
}
}
Run Code Online (Sandbox Code Playgroud)
这将打印 3(而不是您可能期望的 2)。
这样做的原因是add方法java.util.Set比较2个对象是基于equals()方法而不是基于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;
}
Run Code Online (Sandbox Code Playgroud)
那么为什么需要添加hashCode()呢?
HashSet当您在后台使用add 方法时,将调用该equals()方法,并且还将调用hashCode()来决定应将新对象放入的存储桶。hashCode()为了维持和的合同,equals()两者都应该被推翻。equals(),建议hashCode()也覆盖。(反之亦然)。请参阅此链接了解详细信息。hashCode()和 的契约equals():如果对于两个对象说o1和o2,o1.equals(o2)那么和 的true哈希值是相同的。o1o2 should
确保您正确理解这一点,从上面的陈述中并不意味着如果两个对象的哈希值相同,则o1.equals(o2)应该返回true。对于 2 个对象,它们的哈希值可能相同,但o1.equals(o2)返回值可能相同false
看看这里,方法保证Object了什么hashCode()。
请参阅此链接以获取有关此主题的更多详细信息。