我有一个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自动生成。我在像这样的实例化的HashSet中使用Reminder
:private Set<Reminder> localReminders = new HashSet<Reminder>();
更新此集合时,我使用的是localreminders.contains(anotherReminder)
,由于某种原因,我已经尝试了一段时间,它没有调用覆盖的equals
方法。即使比较的提醒中的cronExpression
,subject
,timeout
和type
相同,contains
也会返回false。
到目前为止,我只遇到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
或equals不包含hashcode
属性,因此这无关紧要。
答案 0 :(得分:3)
在equals
方法的实现中可以看到,您调用cronExpression.equals(other.cronExpression)
和subject.equals(other.subject)
和type.equals(other.type)
。如果只有其中一项没有正确实施,那么您将得到错误的结果。请检查您在此方法中使用的所有属性是否正确实现了equals
。
另外,还要检查方法cronExpression.hashCode()
,subject.hashCode()
和type.hashCode()
的实现。它们用在您的hashCode
方法中。
编辑:如果您所说的cronExpression
,subject
和type
是字符串,那么使主方法使用类填充Reminder
的两个对象应该很容易相同的信息并测试方法。为了确定问题出在哪里,您可以致电if(firstReminder.equals(secondReminder))
。
根据我的经验,您可能会遇到琴弦问题。例如,如果其中一个字符串结尾处的空格不同,则另一种或类似类型的问题。
编辑2:好,从您的输入看来,该对象具有相同的字符串。
是否可以扩展Reminder
类,并将子类对象与Reminder
对象进行比较?如果在子类equals
和hashcode
中发生这种情况,则结果可能是错误的。
还要确保您可以记录每个字符串的大小?这很奇怪。 也许您有隐藏的性格。有关更多信息,请参见此: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()
结果。