Я ищу руководство относительно переопределения как hashcode, так и equals в подклассе.
Я нашел аналогичный вопрос здесь: Переопределение equals() и hashCode() в подклассах... с учетом суперполей
Но то, что я хочу, немного отличается.
Представьте себе этот (несколько глупый) пример:
class Food {
String name;
@Override
public boolean equals(Object obj) {
if (obj instanceof Food) {
Food other = (Food)obj;
return name.equals(other.name);
}
return false;
}
@Override
public int hashCode() {
return name.hashCode();
}
}
class Vegetable extends Food {
// No additional fields here
// Some methods here
}
class Fruit extends Food {
// No additional fields here
// Some methods here
}
При условии:
Fruit
и Vegetable
с одинаковым названием не должны быть равныВопросов:
super.equals
instanceof
проверки для подкласса и вызову super.equals
?Fruit
and Vegetable
с тем же именем, имеющие разные хэш-коды? Вы можете просто использовать .getClass()
в Foo
.equals()
:
@Override
public final boolean equals(final Object obj)
{
if (obj == null)
return false;
if (this == obj)
return true;
// Class<?> are signletons, therefore we can use ==/!=
if (getClass() != obj.getClass())
return false;
return name.equals(((Foo) obj).name);
}
.getClass()
вернет класс объекта, поэтому Fruit
or Vegetable
, или даже Food
.
Для .hashCode()
name.hashCode()
отлично. Не забывайте, что нет требования, чтобы хэш-код двух объектов, которые не являются .equals()
, различны. Но если вы хотите, то здесь также можно использовать .getClass()
:
@Override
public final int hashCode()
{
return 31 * getClass().hashCode() + name.hashCode();
}
- Вы ожидали бы, что равные просто будут содержать проверку экземпляра и вызов super.equals?
instanceof
здесь опасен, потому что Food
не абстрактна. Это означает, что equals
не были симметричными.
someFruit.equals(someFood) // will be false
someFood.equals(someFruit) // will be true
Это может не превратиться в проблему, но это то, что вы должны учитывать.
Если вы не хотите разорвать контракт, это случай, когда Food
должна проверить, является ли this.getClass() == obj.getClass()
. Если вы это сделаете, вам также необязательно будет переопределять его в подклассах.
В противном случае это не имеет большого значения. Метод определен по контракту, и вы можете реализовать его, как хотите.
- Как следует структурировать хэш-код в попытке иметь экземпляры Fruit and Vegetable с тем же именем, имеющие разные хэш-коды?
Им не нужно быть разными.
!o1.equals(o2)
тоo1.hashCode() != o2.hashCode()
. Или, может быть, вы неверно истолковали часть «вам все равно». Я имел в виду "это нормально": =)