覆盖的等于不称为

时间:2018-11-21 08:40:50

标签: java equals hashcode

我有一个Reminder类,其中hashcodeequals都被这样重写:

@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自动生成。我在像这样的实例化的HashSet中使用Reminderprivate Set<Reminder> localReminders = new HashSet<Reminder>();

更新此集合时,我使用的是localreminders.contains(anotherReminder),由于某种原因,我已经尝试了一段时间,它没有调用覆盖的equals方法。即使比较的提醒中的cronExpressionsubjecttimeouttype相同,contains也会返回false。
到目前为止,我只遇到equals和/或hashcode实施不正确或根本不实施的答案。任何帮助将不胜感激!

让我知道您是否需要更多信息,例如与此相关的其他代码!

编辑:hashcodeequals中使用的属性都是String,除了timeoutint

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]

我在这里可以看到的唯一区别是,futurenull,而实际上是另一个。但是,由于future或equals不包含hashcode属性,因此这无关紧要。

3 个答案:

答案 0 :(得分:3)

equals方法的实现中可以看到,您调用cronExpression.equals(other.cronExpression)subject.equals(other.subject)type.equals(other.type)。如果只有其中一项没有正确实施,那么您将得到错误的结果。请检查您在此方法中使用的所有属性是否正确实现了equals

另外,还要检查方法cronExpression.hashCode()subject.hashCode()type.hashCode()的实现。它们用在您的hashCode方法中。

编辑:如果您所说的cronExpressionsubjecttype是字符串,那么使主方法使用类填充Reminder的两个对象应该很容易相同的信息并测试方法。为了确定问题出在哪里,您可以致电if(firstReminder.equals(secondReminder))

根据我的经验,您可能会遇到琴弦问题。例如,如果其中一个字符串结尾处的空格不同,则另一种或类似类型的问题。

编辑2:好,从您的输入看来,该对象具有相同的字符串。 是否可以扩展Reminder类,并将子类对象与Reminder对象进行比较?如果在子类equalshashcode中发生这种情况,则结果可能是错误的。

还要确保您可以记录每个字符串的大小?这很奇怪。 也许您有隐藏的性格。有关更多信息,请参见此:Is there an invisible character that is not regarded as whitespace?

祝你好运!

答案 1 :(得分:0)

问题可能出在您的hashcode()方法上。它应该生成一个唯一的代码。有一些准则可以覆盖hashcode()Hashcode Best Practice

如果对象的哈希码不同,则即使它们相等,也不会调用equals()
因为HashSet首先检查两个对象的哈希码,并且如果哈希码相等,则只有它会调用equals()来检查两个对象是否真的相等。

阅读Oracle Javadoc以覆盖hashcode override contract

答案 2 :(得分:0)

如果您希望我们能够为您提供帮助,则需要向我们提供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()。 在the documentation (JRE 7)中,您可以阅读:

  

在合理可行的范围内,由Object类定义的hashCode方法确实为不同的对象返回不同的整数。 (通常通过将对象的内部地址转换为整数来实现,但是JavaTM编程语言不需要这种实现技术。)

因此,具有不同org.quartz.CronExpression实例的相似项都将具有不同的hashCode()结果。