Hashset допускает дубликаты?

Этот вопрос, конечно, не нов, но я нигде не нашел полезного ответа.

Как вы можете видеть в приведенном ниже коде, методы equals и hashcode переопределены, но дубликаты по-прежнему разрешены. Хэш-код был сгенерирован Netbeans автоматически.

@Override
public boolean equals(Object o)
{
    TaskDetails other = (TaskDetails) o;
    if ( (id_subtask == other.id_subtask)
            && ((date.compareTo(other.date)) == 0) )
    {
        System.err.println("Duplicate Entry"+id_subtask+" + "+other.id_subtask);
        return true;
    }
    else
    {
        System.out.println("Good!" +id_subtask+" + "+other.id_subtask);
        return false;
    }

} 

@Override
public int hashCode() {
    int hash = 7;
    hash = 71 * hash + this.id_subtask;
    hash = 71 * hash + this.id_team_member;
    hash = 71 * hash + Float.floatToIntBits(this.nb_hours);
    hash = 71 * hash + (this.date != null ? this.date.hashCode() : 0);
    hash = 71 * hash + (this.comment != null ? this.comment.hashCode() : 0);
    hash = 71 * hash + (this.subtask_name != null ? this.subtask_name.hashCode() : 0);
    System.out.println("Hash : "+hash + "Subtask : " + id_subtask);
    return hash;       
}

Этот код используется для добавления записи в хеш-набор:

TaskDetails newTaskDetails = new TaskDetails
                                (
                                    s.getId_subtask(),
                                    mus.teamMember.getId_team_member(),
                                    f,
                                    mysqlFormat.format(caldate),
                                    c.substring(0, Math.min(c.length(), 100)),
                                    s.getName_subtask()
                                );

                            allTasks.add(newTaskDetails);

(все задачи являются Hashset)

Этот код используется в функциях A и B.

Если выполняется только функция A, она работает нормально. Если функция B выполняется после функции A (поэтому приведенный выше код выполняется дважды), то хэш-набор внезапно принимает дубликаты, даже если срабатывает system.err, говорящий о наличии повторяющейся записи?

Есть ли ошибка в коде, или я просто что-то упустил?

Спасибо за помощь!


person Xaviraan    schedule 10.12.2012    source источник
comment
Я подозреваю, что что-то манипулирует newTaskDetails, из-за которого изменяется хеш-значение.   -  person kosa    schedule 10.12.2012
comment
для какого класса вы переопределяете эти методы?   -  person Nikolay Kuznetsov    schedule 10.12.2012
comment
Что именно вы имеете в виду, говоря, что принимает дубликаты? Весь объект один и тот же, или вы просто имеете в виду повторяющиеся идентификаторы?   -  person Zutty    schedule 10.12.2012
comment
возможный дубликат Java HashSet допускает дублирование; проблема с сопоставимым?   -  person Raedwald    schedule 12.07.2013


Ответы (5)


вы используете 2 поля, чтобы считать 2 объекта «равными», но вы используете более 2 полей для построения хэш-кода. ваш метод hashCode() не может быть более конкретным, чем ваш метод equals(). как правило, ваш метод hashCode() не должен использовать какие-либо поля, которые не использует ваш метод equals() (однако он может использовать меньше). говоря более технически, если 2 объекта "равны", они должны иметь одинаковый хэш-код (обратное не требуется).

person jtahlborn    schedule 10.12.2012
comment
Спасибо jtalborn и Йохен! Кажется, пока работает! Вероятно, поэтому хэш-код для некоторых объектов был одинаковым. - person Xaviraan; 11.12.2012

Вы нарушаете требование согласованности между hashCode() и equals(). Если два объекта равны в соответствии с equals(), они также должны иметь одинаковый хэш. Поскольку метод equals учитывает только два поля, а hashCode — больше, это требование не выполняется.

person Jochen    schedule 10.12.2012

Ваша проблема в том, что реализация hashCode() не соответствует equals(). Оба метода должны использовать одни и те же атрибуты вашего объекта.

Вероятно, в вашей реализации hashCode() отличается, даже если equals() оценивается как true. В этом случае (разные hashCode) объекты разные для HashMap.

Пожалуйста, исправьте свои реализации, чтобы использовать те же атрибуты. Тогда ошибка должна исчезнуть.

person Uwe Plonus    schedule 10.12.2012

Из javadoc от Object

If two objects are equal according to the equals(Object) method, then
calling the hashCode method on each of the two objects must produce the
same integer result. 

Ваши хэш-коды различны для двух объектов, которые равны согласно методу equals(Object), поэтому другой код HashSet будет делать неверные предположения и возвращать неверные результаты.

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

person Edwin Buck    schedule 10.12.2012

Это повторяющийся вопрос, см. мой предыдущий ответ.

Поведение, при котором java.util.HashSet допускает дублирование, вызвано тем, что хэш-код объектов в java.util.HashSet может измениться.

Обычно это происходит, когда хеш-код объекта создается из изменяемых полей.

person Nick Holt    schedule 10.12.2012