Переопределение hashCode() - это достаточно хорошо?

Для класса, поля которого являются исключительно примитивными, например:

class Foo
{
    int a;
    String b;
    boolean c;
    long d;

    boolean equals(Object o)
    {
        if (this == o) return true;
        if (!(o instanceof Foo)) return false;
        Foo other = (Foo) o;
        return a == other.a && b.equals(other.b) && c == other.c && d = other.d;
    }
}

Является ли это достаточно "хорошим" способом написать hashCode()?

boolean hashCode()
{
    return (b + a + c + d).hashCode();
}

То есть я создаю String из тех же полей, которые использует equals(), а затем просто используйте String#hashCode().

Изменить: Я обновил свой вопрос, включив в него поле long. Как следует обрабатывать long в hashCode()? Просто позвольте этому переполнению int?

Ответы

Ответ 1

Ваш хэш-код удовлетворяет этому свойству, что если два объекта равны, то их хэш-коды должны быть равны. Таким образом, это "достаточно хорошо". Однако довольно просто создать коллизии в хеш-кодах, что ухудшит производительность хэш-структуры данных.

Я бы выполнил его несколько иначе:

public int hashCode() {
    return a * 13 + b.hashCode() * 23 + (c? 31: 7);
}

Вы должны проверить документацию для метода hashCode() Object. В нем описаны вещи, которые должен удовлетворять хэш-код.

Ответ 2

Все зависит от того, как будут выглядеть ваши данные. В большинстве случаев это было бы хорошим подходом. Если у вас часто заканчивается число b с номером, то вы получите несколько повторяющихся кодов для неравных объектов, как показывает ответ JacobM. Если вы заранее знаете, что b в конце концов никогда не будет иметь числового значения в конце, то это разумный алгоритм хэширования.