Java hashcode, основанный на идентичности
Поведение Object.hashCode() по умолчанию заключается в том, чтобы вернуть по существу "адрес" объекта, чтобы a.hashCode() == b.hashCode() тогда и только тогда, когда a == b. Как я могу получить это поведение в пользовательском классе, если суперкласс уже определяет hashCode()? Например:
class A {
public int hashCode() {
return 0;
}
}
class B extends A {
public int hashCode() {
// Now I want to return a unique hashcode for each object.
// In pythonic terms, it'd look something like:
return Object.hashCode(this);
}
}
Идеи?
Ответы
Ответ 1
System.identityHashCode(Object) обеспечивает такое поведение.
Вы бы это сделали:
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
}
Пожалуйста, проверьте метод equals, чтобы он возвращал true, если оба объекта одинаковы. В противном случае это нарушит поведение, описанное для equals и hashCode. (Чтобы быть верным, метод equals должен возвращать false, если вы получаете разные хэш-коды для двух объектов.) Чтобы обеспечить реализацию equals(), которые соответствуют заданному методу hashCode():
public boolean equals(Object other){
return this == other;
}
Ответ 2
Используйте System.identityHashCode()
. Это то, что использует IdentityHashMap
.
Вы должны быть крайне опасаться переопределения существующего hashCode()
с этим, хотя, поскольку вы можете разорвать контракт hashCode, будучи двумя объектами, которые:
если a.equals(b), то a.hashCode() должен быть равен b.hashCode()
Вы можете сломать это, переопределив существующее поведение, или вам может потребоваться переопределить equals() тоже.
Ответ 3
Как сказал Мнемент, все, я хотел бы указать, что hashCode(), возвращающий 0 (или любое постоянное значение), является действительным (хотя и хромым). hashCode() может (и должен) возвращать разные значения для a и b, только если! a.equals(b).
Так, например, у вас есть
class A {
public int hashCode() {
return 0;
}
public boolean equals(Object o) {
return o instanceof A; // all objects are equal
}
}
class B extends A {
public int hashCode() {
return System.identityHashCode(this);
}
public boolean equals(Object o) {
return this.hashCode().equals(o.hashCode());
}
}
Теперь вы создаете два объекта:
A a = new A();
A b = new B();
И вдруг a.equals(b), но! b.equals(a). Конечно, в более реальной жизни equals() в будет более сложным, но проблема все еще сохраняется. Чтобы избавиться от этой проблемы, вы всегда хотите вызвать
if (super.equals(o)) return true;
в начале новых equals().
И так как переопределение hashCode() строго связано с переопределением equals(), вы хотите убедиться, что везде super.equals() вернётся true для любых двух заданных объектов, новый hashCode() вернет super.hashCode().