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

时间:2010-09-11 19:50:38

标签: java hashset

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

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

这是我的代码

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");

这是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);
    }
}

这是我得到的输出

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)

3 个答案:

答案 0 :(得分:39)

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

另见:


提示:如果您使用的是Eclipse之类的IDE,您也可以自动生成它们。右键单击Move类的某个位置,选择 Source&gt;生成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;
}

答案 1 :(得分:8)

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

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

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

例如(虽然可能是非最优的,你可能想要一个null安全等于 - 如果可以,你的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;
}

答案 2 :(得分:1)

您必须覆盖equals()hasCode()

这可能是一种选择。

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()  );
    }
}

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

了解更多信息:

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

第8项:当你覆盖以下的等于时,总是覆盖hashCode:“Effective Java”http://bit.ly/cd7uUl