web-dev-qa-db-ja.com

HashSetは、2つのオブジェクトが同じであることを認識していないようです。

HashSetを使用して、作成したクラスのオブジェクトを保存しようとしていますが、同じオブジェクトに2つの異なるハッシュがあるようです。そのため、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)
26

Moveインスタンスの状態に対して同じObject#hashCode()値を返すようにするには、Moveクラスの hashCode() メソッドをオーバーライドする必要があります。 Object#equals() もオーバーライドすることを忘れないでください。

以下も参照してください。


ヒント:IDE like Eclipse を使用している場合は、それらを自動生成します。Moveクラスのどこかを右クリックし、Source> Generate hashCode()and 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;
}
39
BalusC

HashSetは、hashCode()とequals()の呼び出しに基づいて等価性を判断します。これらは実装していないため、Objectから継承します。 ObjectのhashCodeメソッドとequalsメソッドは、参照が等しいかどうかに基づいています。

そのため、if(move1.hashCode()==new Move(t,s).hashCode())はfalseです。 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;
}
8
nos

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と等しいかどうか)。

詳細については:

JavaでequalsとhashCodeをオーバーライドするときに考慮すべき問題は何ですか?

アイテム8:次の値と等しい値をオーバーライドする場合は常にhashCodeをオーバーライドします: "Effective Java" http://bit.ly/cd7uUl

1
OscarRyz