Переопределенный равный не называется - PullRequest
0 голосов
/ 21 ноября 2018

У меня есть класс Reminder, который имеет как hashcode, так и equals переопределенный следующим образом:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((cronExpression == null) ? 0 : cronExpression.hashCode());
    result = prime * result + ((subject == null) ? 0 : subject.hashCode());
    result = prime * result + timeout;
    result = prime * result + ((type == null) ? 0 : type.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Reminder))
        return false;
    Reminder other = (Reminder) obj;
    if (cronExpression == null) {
        if (other.cronExpression != null)
            return false;
    } else if (!cronExpression.equals(other.cronExpression))
        return false;
    if (subject == null) {
        if (other.subject != null)
            return false;
    } else if (!subject.equals(other.subject))
        return false;
    if (timeout != other.timeout)
        return false;
    if (type == null) {
        if (other.type != null)
            return false;
    } else if (!type.equals(other.type))
        return false;
    return true;
}

Оба переопределения были автоматически сгенерированы с использованием Eclipse.Я использую Reminder в экземпляре HashSet, например: private Set<Reminder> localReminders = new HashSet<Reminder>();

При обновлении этого набора я использую localreminders.contains(anotherReminder), и по какой-то причине я пытался выяснить дляНекоторое время назад он не вызывает переопределенный метод equals.Даже если cronExpression, subject, timeout и type сравниваемых напоминаний одинаковы, contains возвращает ложь.
До сих пор я встречал только ответы, где equals и / илиhashcode были реализованы неправильно или не реализованы вообще.Буду очень признателен за любую помощь!

Дайте мне знать, если вам нужна дополнительная информация, например, дополнительный код для этого!

РЕДАКТИРОВАТЬ: свойства, используемые в hashcode и equals, все String, за исключением timeout, который равен int.

EDIT2: во время отладки у меня в настоящее время есть два напоминания в моем HashSet:
Reminder [cronExpression=0 10 10 ? * *, subject=, type=OTHER_TYPE, audioPath=/other_type_reminder.mp3, muted=false, future=DelegatingErrorHandlingRunnable for Task@af94b0, timeout=35940]

Reminder [cronExpression=50 53 10 ? * *, subject=sub, type=TYPE, audioPath=/type_reminder.mp3, muted=false, future=DelegatingErrorHandlingRunnable for ReminderTask@f1f373, timeout=35940]

Тот, который я проверяю, содержится ли он в моем наборе, выглядит следующим образом:
Reminder [cronExpression=50 53 10 ? * *, subject=sub, type=TYPE, audioPath=/type_reminder.mp3, muted=false, future=null, timeout=35940]

Единственное отличие, которое я могу заметить, заключается в том, что в одном, future равно null, в то время как оно фактически установлено в другом.Но так как свойство future не включено ни в hashcode, ни в 'equals', это не должно иметь значения.

Ответы [ 3 ]

0 голосов
/ 21 ноября 2018

Проблема может быть в вашем hashcode() методе.Он должен генерировать уникальный код.Существуют некоторые рекомендации по переопределению hashcode(). Рекомендации по хэш-коду

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

Считайте Oracle Javadoc для переопределения контракт переопределения хеш-кода

0 голосов
/ 21 ноября 2018

Вы должны предоставить нам импорт класса Reminder, если хотите, чтобы мы могли вам помочь.

Для вашей культуры и любопытства : java.util.HashSet.contains(Object o), чтениекод, на который он указывает:

public boolean containsKey(Object key) {
    return getNode(hash(key), key) != null;
}

, который сам по себе указывает на:

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Как видите, важной частью вашей реализации является Reminder.hashCode().


Относительно вашей конкретной проблемы : Поскольку вы, вероятно, используете quartz для org.quartz.CronExpression, вы можете видеть, что метод org.quartz.CronExpression.hashCode() не реализован, поэтому он вызывает своего родителя hashCode(), чтоэто Object.hashCode().Из документации (JRE 7) вы можете прочитать:

Насколько это практически целесообразно, метод hashCode, определенный классом Object, возвращает разные целые числа для разных объектов.(Обычно это реализуется путем преобразования внутреннего адреса объекта в целое число, но этот метод реализации не требуется языком программирования JavaTM.)

Таким образом, оба одинаковых элемента с различным экземпляром org.quartz.CronExpression будет иметь другой hashCode() результат.

0 голосов
/ 21 ноября 2018

Как вы можете видеть в реализации метода equals, вы вызываете cronExpression.equals(other.cronExpression) и subject.equals(other.subject) и type.equals(other.type).Если только один из них не реализован правильно, вы получите неправильный результат.Пожалуйста, проверьте, все ли свойства, которые вы используете в этом методе, имеют правильную реализацию equals.

. Кстати, проверьте также реализацию методов cronExpression.hashCode(), subject.hashCode() и type.hashCode().Они используются в вашем методе hashCode.

Редактировать: Если, как вы сказали, cronExpression, subject и type являются строками, вам будет легко сделать так, чтобы метод main заполнял два объекта изКласс Reminder с той же информацией и проверить методы.Чтобы быть уверенным, в чем проблема, вы можете позвонить if(firstReminder.equals(secondReminder)).

Из моего опыта у вас могут возникнуть проблемы со строками.Например, если одна из строк с пробелом в конце отличается от другой или аналогичной проблемы.

Редактировать 2: Хорошо, из вашего ввода Кажется, что эти объекты имеют одинаковые строки.Можно ли расширить класс Reminder и сравнить ли объект дочернего класса с объектом Reminder?Если это происходит в дочернем классе, могут быть реализованы equals и hashcode, и тогда результат может быть неправильным.

Также просто убедитесь, что вы можете записать размер каждой строки?Это очень странно.Может быть, вы можете иметь скрытый характер.См. Это для получения дополнительной информации: Есть ли невидимый символ, который не считается пробелом?

Удачи!

...