Вопрос-ответ

Best implementation for hashCode method for a collection

Лучшая реализация метода hashCode для коллекции

Как нам выбрать наилучшую реализацию hashCode() метода для коллекции (при условии, что метод equals был переопределен правильно)?

Переведено автоматически
Ответ 1

Лучшая реализация? Это сложный вопрос, потому что это зависит от шаблона использования.

Почти для всех случаев разумно хорошая реализация была предложена в "Эффективной Java" Джоша Блоха в пункте 8 (второе издание). Лучше всего посмотреть его там, потому что автор объясняет, почему этот подход хорош.

Краткая версия


  1. Создайте int result и присвоите ненулевое значение.


  2. Для каждого поля, f протестированного в equals() методе, вычислите хэш-код c с помощью:



    • Если поле f равно a boolean: вычислить(f ? 0 : 1);

    • Если поле f равно byte, char, short или int: вычислить (int)f;

    • Если поле f равно a long: вычислить(int)(f ^ (f >>> 32));

    • Если поле f равно a float: вычислитьFloat.floatToIntBits(f);

    • Если поле f является a double: вычислите Double.doubleToLongBits(f) и обработайте возвращаемое значение, как любое длинное значение;

    • Если поле f является объектом: используйте результат hashCode() метода или 0, если f == null;

    • Если поле f является массивом: рассматривайте каждое поле как отдельный элемент и вычисляйте значение хэша рекурсивным способом и объединяйте значения, как описано далее.


  3. Объедините хэш-значение c с result:


    result = 37 * result + c

  4. Возврат result


Это должно привести к правильному распределению значений hash для большинства ситуаций использования.

Ответ 2

Если вас устраивает эффективная реализация Java, рекомендованная dmeister, вы можете использовать вызов библиотеки вместо того, чтобы создавать свою собственную:

@Override
public int hashCode() {
return Objects.hash(this.firstName, this.lastName);
}

Для этого требуется либо Guava (com.google.common.base.Objects.hashCode), либо стандартная библиотека Java 7 (java.util.Objects.hash), но работает так же.

Ответ 3

Хотя это связано с Android документацией (Wayback Machine) и моим собственным кодом на Github, это будет работать для Java в целом. Мой ответ является расширением ответа dmeister с использованием только кода, который намного легче читать и понимать.

@Override 
public int hashCode() {

// Start with a non-zero constant. Prime is preferred
int result = 17;

// Include a hash for each field.

// Primatives

result = 31 * result + (booleanField ? 1 : 0); // 1 bit » 32-bit

result = 31 * result + byteField; // 8 bits » 32-bit
result = 31 * result + charField; // 16 bits » 32-bit
result = 31 * result + shortField; // 16 bits » 32-bit
result = 31 * result + intField; // 32 bits » 32-bit

result = 31 * result + (int)(longField ^ (longField >>> 32)); // 64 bits » 32-bit

result = 31 * result + Float.floatToIntBits(floatField); // 32 bits » 32-bit

long doubleFieldBits = Double.doubleToLongBits(doubleField); // 64 bits (double) » 64-bit (long) » 32-bit (int)
result = 31 * result + (int)(doubleFieldBits ^ (doubleFieldBits >>> 32));

// Objects

result = 31 * result + Arrays.hashCode(arrayField); // var bits » 32-bit

result = 31 * result + referenceField.hashCode(); // var bits » 32-bit (non-nullable)
result = 31 * result + // var bits » 32-bit (nullable)
(nullableReferenceField == null
? 0
: nullableReferenceField.hashCode());

return result;

}

Редактировать

Обычно, когда вы переопределяете hashcode(...), вы также хотите переопределить equals(...). Итак, для тех, кто будет или уже реализован equals, вот хорошая ссылка с моего Github...

@Override
public boolean equals(Object o) {

// Optimization (not required).
if (this == o) {
return true;
}

// Return false if the other object has the wrong type, interface, or is null.
if (!(o instanceof MyType)) {
return false;
}

MyType lhs = (MyType) o; // lhs means "left hand side"

// Primitive fields
return booleanField == lhs.booleanField
&& byteField == lhs.byteField
&& charField == lhs.charField
&& shortField == lhs.shortField
&& intField == lhs.intField
&& longField == lhs.longField
&& floatField == lhs.floatField
&& doubleField == lhs.doubleField

// Arrays

&& Arrays.equals(arrayField, lhs.arrayField)

// Objects

&& referenceField.equals(lhs.referenceField)
&& (nullableReferenceField == null
? lhs.nullableReferenceField == null
: nullableReferenceField.equals(lhs.nullableReferenceField));
}
Ответ 4

Лучше использовать функциональность, предоставляемую Eclipse, которая выполняет довольно хорошую работу, и вы можете приложить свои усилия и энергию к разработке бизнес-логики.

java