Java HashSet 似乎没有意识到两个对象是相同的。

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3692426/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 03:31:25  来源:igfitidea点击:

HashSet does not seem to realize that two objects are the same.

javahashset

提问by efficiencyIsBliss

I'm trying to use HashSet to store objects of a class that I created, but apparently the same objects seem to have two different hashes, which is why the contains method does not realize that the object is already in the HashSet. This leads to my program running out of heap memory.

我正在尝试使用 HashSet 来存储我创建的类的对象,但显然相同的对象似乎有两个不同的哈希值,这就是 contains 方法没有意识到该对象已经在 HashSet 中的原因。这导致我的程序耗尽堆内存。

I don't think I'm doing anything wrong, but I wanted a second opinion anyway. I've done similar operations before which all worked fine, which makes this particularly annoying. I'd appreciate any help.

我不认为我做错了什么,但无论如何我想要第二个意见。我之前做过类似的操作,但一切正常,这让这特别烦人。我很感激任何帮助。

Here's my code

这是我的代码

move1 = new Move(t,s);
if(move1.hashCode()==new Move(t,s).hashCode())
    System.out.println("match");
move2 = new Move(s,t);
moves.add(move1); 
moves.add(move2);
if(moves.contains(new Move(t,s)))
    System.out.println("match found");

Here's the Move class:

这是 Move 类:

public class Move {
    private int move1;
    private int move2;

    Move(int m1, int m2)
    {
        move1 = m1;
        move2 = m2;
    }

    public String toString()
    {
         return String.valueOf(move1)+" "+String.valueOf(move2);
    }
}

Here's the output I get

这是我得到的输出

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.addEntry(HashMap.java:797)
    at java.util.HashMap.put(HashMap.java:431)
    at java.util.HashSet.add(HashSet.java:194)
    at makeMove.<init>(makeMove.java:33)

采纳答案by BalusC

You need to override the Object#hashCode()method in the Moveclass to let it return the same hashCode()value for the state of the Moveinstance. Don't forget to override Object#equals()as well.

您需要覆盖类中的Object#hashCode()方法,Move让它hashCode()Move实例的状态返回相同的值。不要忘记覆盖Object#equals()

See also:

也可以看看:



Hint: if you're using an IDE like Eclipse, you can also just autogenerate them. Rightclick somewhere the Moveclass, choose Source > Generate hashCode() and equals(). Here is how it look like then:

提示:如果您使用的是Eclipse 之类的 IDE ,您也可以自动生成它们。右键单击Move该类的某处,选择Source > Generate hashCode() 和 equals()。这是它的样子:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + move1;
    result = prime * result + move2;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Move other = (Move) obj;
    if (move1 != other.move1)
        return false;
    if (move2 != other.move2)
        return false;
    return true;
}

回答by nos

HashSet will determine equality based on calling hashCode() and equals(). You have not implemented these, so you'll inherite them from Object. The hashCode and equals methods of Object is just based on whether the references are equal.

HashSet 将根据调用 hashCode() 和 equals() 来确定相等性。您尚未实现这些,因此您将从 Object 继承它们。Object 的 hashCode 和 equals 方法只是基于引用是否相等。

That's why if(move1.hashCode()==new Move(t,s).hashCode())is false. move1 is a different instance than the instance created by calling new Move(t,s).hashCode()

这就是为什么if(move1.hashCode()==new Move(t,s).hashCode())是假的。move1 是与通过调用 new Move(t,s).hashCode() 创建的实例不同的实例

You'll need to implement hashCode and equals in your Move class.

您需要在 Move 类中实现 hashCode 和 equals。

e.g.(though perhaps non-optimal, and you might want a null safe equals - have your IDE generate them if it can)

例如(虽然可能不是最佳的,你可能想要一个空安全的等号——如果可以的话,让你的 IDE 生成它们)

public int hashCode() {
    return move1 ^ move2 +;
}

public boolean equals(Object o) {
  if(!other instanceof Move) 
      return false;

  Move other = (Move)o;

  return other.move1 == move1 && other.move2 == move2;
}

回答by OscarRyz

You have to override equals()and hasCode()

你必须覆盖equals()hasCode()

This may be an option.

这可能是一种选择。

import static java.lang.System.out;
public class Move {
    private int move1;
    private int move2;

    Move(int m1, int m2) {
        move1 = m1;
        move2 = m2;
    }

    public String toString() {
         return String.valueOf(move1)+" "+String.valueOf(move2);
    }

    public int hashCode() {
        return move1 * 31 + move2 * 31;
    }
    public boolean equals( Object other ) {
        if( this == other ) { return true; }
        if( other instanceof Move ) {
            Move m2 = ( Move ) other;
            return this.move1 == m2.move1 && this.move2 == m2.move2;
        }
        return false;
    }

    public static void main( String  [] args ) {
        out.println( new Move(2,3).equals( new Move(2,3)));
        out.println( new Move(1,1).hashCode() == new Move(1,1).hashCode()  );
    }
}

You have to define if the order of the move is relevant ( 1,2 isequals to 2,1 or not )

您必须定义移动的顺序是否相关( 1,2 等于 2,1 或不相关)

For more information:

想要查询更多的信息:

What issues should be considered when overriding equals and hashCode in Java?

在 Java 中重写 equals 和 hashCode 时应该考虑哪些问题?

Item 8: always override hashCode when you override equals from: "Effective Java" http://bit.ly/cd7uUl

第 8 项:当您覆盖以下内容时始终覆盖 hashCode:“Effective Java” http://bit.ly/cd7uUl