Редактировать: Подготовить мои объекты для использования в HashMap.
Прочитав немного о том, как генерировать хеш-код, я немного запутался сейчас же. Мой (возможно, тривиальный) вопрос, Как я должен реализовать метод hashCode, когда у меня есть одно поле, которое я мог бы использовать? Могу ли я использовать поля напрямую? Если я правильно понимаю, значения для hashCode не должны изменяться в течение срока службы объекта, и у меня есть только поданный идентификатор, который соответствует этому, но я читал в другом месте, что не следует использовать идентификатор ... независимо от того, как будет выглядеть функция hashCode, основанная на этом (уникальном и неизменном) значении? Метод equals также основан только на id.
Если ваш объект является изменяемым, то его хэш-код может меняться с течением времени. Конечно, вы должны предпочесть неизменяемые объекты ( Эффективное Java 2-е издание, Правило 15: Минимизируйте изменчивость ).
Вот рецепт хэш-кода от Джоша Блоха, из Эффективное 2-е издание Java, пункт 9: Всегда переопределяйте hashCode
, когда вы переопределяете равным
:
int
, называемой result
. int
c
для каждого поля:
логическим
, вычислить (f? 1: 0)
байт, char, short, int
, вычислить (int) f
, вычислить (int) (f ^ (f >>> 32))
float
, вычислить Float.floatToIntBits (f)
double
, вычислить Double.doubleToLongBits (f)
, затем хэшировать в результате длинное
, как указано выше. равно
сравнивает поле, рекурсивно вызывая равно
, рекурсивно вызывает hashCode
в поле. Если значение поля равно null
, вернуть 0. Arrays.hashCode
, добавленных в выпуске 1.5. c
в результат
следующим образом: result = 31 * result + c;
Было бы правильно следовать рецепту как есть, даже всего с одним полем. Просто выполните соответствующее действие в зависимости от типа поля.
Обратите внимание, что есть библиотеки, которые действительно упрощают это для вас, например HashCodeBuilder
из Apache Commons Lang или просто Arrays.hashCode / deepHashCode
из java.util.Arrays
.
Эти библиотеки позволяют вам просто написать что-то вроде этого:
@Override public int hashCode() {
return Arrays.hashCode(new Object[] {
field1, field2, field3, //...
});
}
Вот более полный пример использования построителей из Apache Commons Lang для облегчения удобного и удобочитаемого равно
, hashCode
, toString
и compareTo
:
import org.apache.commons.lang.builder.*;
public class CustomType implements Comparable<CustomType> {
// constructors, etc
// let's say that the "significant" fields are field1, field2, field3
@Override public String toString() {
return new ToStringBuilder(this)
.append("field1", field1)
.append("field2", field2)
.append("field3", field3)
.toString();
}
@Override public boolean equals(Object o) {
if (o == this) { return true; }
if (!(o instanceof CustomType)) { return false; }
CustomType other = (CustomType) o;
return new EqualsBuilder()
.append(this.field1, other.field1)
.append(this.field2, other.field2)
.append(this.field3, other.field3)
.isEquals();
}
@Override public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(field1)
.append(field2)
.append(field3)
.toHashCode();
}
@Override public int compareTo(CustomType other) {
return new CompareToBuilder()
.append(this.field1, other.field1)
.append(this.field2, other.field2)
.append(this.field3, other.field3)
.toComparison();
}
}
Эти четыре метода могут быть чрезвычайно утомительными для написания, и может быть трудно гарантировать, что все контракты соблюдаются, но, к счастью, библиотеки могут, по крайней мере, облегчить эту работу. Некоторые IDE (например, Eclipse) также могут автоматически генерировать некоторые из этих методов.
равно
hashCode
, когда вы отменяете , равно
toString
Comparable
Если вы хотите, чтобы объекты с разными идентификаторами идентифицировались этим идентификатором, все, что вам нужно сделать, это вернуть его / сравнить.
private final int id;
public int hashCode() { return id; }
public boolean equals(Object o) {
return o instanceof ThisClass && id == ((ThisClass)o).id;
}
Не имеет значения, сколько полей используется для вычисления hashCode. Но важно работать с equals () . Если A равно B, их хэш-код должен быть таким же.
Если вы ненавидите hashCode :) и ваш объект никогда не помещается в контейнеры на основе хешей (HashMap, HashSet ..), просто оставьте hashCode () в покое, пусть его базовый класс вычислит hashCode.