2012-06-11 5 views
2

, как для определения лица:как переопределить этот метод hashCode?

public class Person { 
    private int id; 
    private int characteristics; 
    public boolean equals (Object obj) { 
      if (obj == this) { 
       return true; 
      } 
      if (obj instanceof Person) { 
       if (id == ((Person) obj).id) { 
        return true; 
       } else if (characteristics == ((Person) obj).characteristics) { 
        return true; 
       } 
      } 
      return false; 
    } 
} 

причина 2 Person объекты a и b должны иметь одинаковый хеш-код, если a.equals(b) возвращает true, как я должен реализовать метод hashCode?

решение

мой equals реализация метода является неправильным в соответствии с протоколом эквивалентности в Java: транзитивности не удовлетворен: a.id = 1, a.characteristic = 2, b.id = 1, b.characteristic = 3, c.id = 2, c.characteristic = 3; a.equals(b) == true, b.equals(c) == true, но a.equals(c) == false.

+1

Вы можете XOR переменные id и характеристик. –

+0

Для записи вы можете преобразовать второй набор этих 'if' в return, т.е. 'return obj instanceof Person && (id == ((Person) obj) .id || характеристики == ((Person) obj). характеристики);'. Вы также должны позаботиться о том, чтобы 'return false' в конце вашего текущего кода, так как ваш метод' equals' может работать, не возвращая ничего. – SimplyPanda

+3

@SimplyPanda Это совершенно неправильно на первом. 'return obj == this;' будет возвращать false, если 'obj' - не тот же экземпляр, но все равно может быть равен по значению. – cdhowie

ответ

5

Поскольку ваш класс рассматривает объекты равны, когда-либо из их соответствующих id или characteristics полей равны, только хеш-код, который вы можете разумно использовать здесь является постоянной величиной для всех экземпляры:

public int hashCode() { 
    return 0; 
} 

Это заставит поиск на основе хэша выполнить ужасно.

Испытание в equals() - это, как правило, плохая идея; объекты на самом деле не равно, не так ли? Может быть, они просто «друг для друга»? Возможно, вам стоит рассмотреть возможность оставить equals() и реализовать другой метод сравнения.


Как Thomasz отметил, ваш equals() тест не является транзитивным; если a.equals(b) && b.equals(c) истинно, тогда a.equals(c) должен быть правдой. Это не true с вашей перегрузкой, и поэтому ваша реализация приведет к прекращению действия контракта: equals(). Я настоятельно призываю вас выполнить этот тест другим способом и оставить только equals().

+2

это правильный ответ :) (equals хорош для set/collections, просто hashcode не работает в случае OP) – bestsss

1

Это то, что автоматически генерируется для вашего класса:

@Override 
public int hashCode() { 
    int result = id; 
    result = 31 * result + characteristics; 
    return result; 
} 

И после нескольких реорганизаций:

@Override 
public int hashCode() { 
    return 31 * id + characteristics; 
} 

И для записи, это только у меня или Ваш equals() сломана? Вы считаете, что два объекта равны, если либо id s, либо characteristics равны, но не обязательно оба из них. Это означает, что ваше равенство не равно transitive, который может иметь действительно неожиданные побочные эффекты, когда ваш объект переходит в пустыню.

Вот приличная реализация:

@Override 
public boolean equals(Object o) { 
    if (this == o) { 
     return true; 
    } 
    if (!(o instanceof Person)) { 
     return false; 
    } 

    Person person = (Person) o; 
    return characteristics == person.characteristics && id == person.id; 
} 
+1

Это не похоже точно для меня, разве метод equals() OP не указывает, если (id == person.id) || (характеристики == person.characteristics) – NominSim

+0

ДА: 'if (id == person.id) || (характеристики == person.characteristics) ' –

+0

@NominSim: вы правы. Однако определение 'equals()' by OP не является транзитивным, мой 'hashCode()' действителен для правильного 'equals()' - который я заметил позже. Я принимаю ваш downvote со смирением, однако я считаю, что у OP больше проблем ... –

0

Если с той же id означает всегда иметь тот же characteristics (что представляется необходимым для вашего equals() быть действительными), то ваш хэш-код может использовать characteristics в одиночку:

@Override 
public int hashCode() { 
    return characteristics; 
} 

Если это не так, то вы может захотеть пересмотреть использование Java-равенства, чтобы выразить это отношение, как предлагает @cdhowie.

Смежные вопросы