Подтвердить что ты не робот

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

Здесь вывод я получаю

Исключение в потоке "main" java.lang.OutOfMemoryError: Java heap space     в java.util.HashMap.addEntry(HashMap.java:797)     в java.util.HashMap.put(HashMap.java:431)     в java.util.HashSet.add(HashSet.java:194)     на makeMove. (makeMove.java:33)

4b9b3361

Ответ 1

Вам нужно переопределить метод Object#hashCode() в классе Move, чтобы он возвращал то же значение hashCode() для состояние экземпляра Move. Не забудьте переопределить Object#equals().

См. также:


Совет. Если вы используете IDE, например Eclipse, вы также можете просто автогенерировать их, Rightclick где-нибудь в классе 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;
}

Ответ 2

HashSet будет определять равенство, основанное на вызове hashCode() и equals(). Вы их не реализовали, поэтому вы унаследуете их от Object. Метод hashCode и equals объекта Object основан только на том, равны ли ссылки.

Вот почему if(move1.hashCode()==new Move(t,s).hashCode()) является ложным. move1 - это другой экземпляр, чем экземпляр, созданный вызовом new Move (t, s).hashCode()

Вам нужно будет реализовать hashCode и равно в классе Move.

например (хотя, возможно, и не оптимально, и вам может понадобиться нулевой безопасный эквивалент - если ваша 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;
}

Ответ 3

Вы должны переопределить 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 или нет)

Для получения дополнительной информации:

Какие проблемы следует учитывать при переопределении equals и hashCode в Java?

Пункт 8: всегда переопределять hashCode, когда вы переопределяете равные значения: "Эффективная Java" http://bit.ly/cd7uUl