java.util.Date equals()不';似乎没有如预期的那样工作 问题
我有一个java.util.Date equals()不';似乎没有如预期的那样工作 问题,java,date,Java,Date,我有一个映射,以及数据库中具有effectiveDate属性的对象列表,我想检查映射中的Date键是否与数据库中的任何effectiveDate键相等-如果是,请使用Foo执行操作 代码如下所示: for (Bar bar : databaseBars) { Foo foo = new Foo(); if (dateMap.containsKey(bar.getEffectiveDate()) { foo = dateMap.get(bar.getEffectiveDate())
映射
,以及数据库中具有effectiveDate
属性的对象列表,我想检查映射中的Date
键是否与数据库中的任何effectiveDate
键相等-如果是,请使用Foo
执行操作
代码如下所示:
for (Bar bar : databaseBars) {
Foo foo = new Foo();
if (dateMap.containsKey(bar.getEffectiveDate()) {
foo = dateMap.get(bar.getEffectiveDate());
}
// do stuff with foo and bar
}
然而,dateMap.containsKey
调用总是返回false,即使我确信有时会返回false
调查
作为合理性检查,我已打印出日期的长值,以及equals()
调用和compareTo()调用的结果:
for (Date keyDate : dateMap.keySet()) {
if (keyDate == null) {
continue; // make things simpler for now
}
Date effDate = bar.getEffectiveDate();
String template = "keyDate: %d; effDate: %d; equals: %b; compareTo: %d\n";
System.out.printf(template, keyDate.getTime(), effDate.getTime(), effDate.equals(keyDate), effDate.compareTo(keyDate));
}
结果是:
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
问题:
1) 不应该等于
和比较
一致吗?(我假设java.util.Date
的实现至少应该尝试遵循java.lang.Comparable
的建议)
2) :
因此,当且仅当getTime方法为这两个对象返回相同的long值时,这两个日期对象才相等
…看起来getTime
方法为这两个日期返回相同的长值,但equal
返回false。你知道为什么会这样吗?我到处找,但没有找到任何人描述同样的问题
另外,我一直在使用java.util.Date
。请不要只是推荐JodaTime
p.p.S.我意识到我可以改变这段代码的结构,或许可以让它正常工作。但这应该行得通,我不想只是解决它,除非这是一个已知的问题或其他什么。这似乎是错误的。从数据库返回的Date
对象可能是java.sql.Timestamp
,它不能等于java.util.Date
对象。我只需要使用从getTime()
返回的long,并将其用作HashMap
中的一个键,正如所暗示和指出的,这里的问题是java.util.Date
的实现
java.util.Date
在java.sql
包中扩展了3个类,所有这些类似乎都做了类似的事情,但它们在java中的区别并不清楚(似乎它们存在的原因只是为了使java类更准确地与sql数据类型对齐)-有关它们差异的更多信息,退房
现在,在一个看起来很严重的设计缺陷中,有人决定让-timestamp.equals(date)
返回false,即使date.equals(timestamp)
返回true。好主意
我写了几行代码,看看哪个java.sql
类演示了这个荒谬的属性——显然它只是Timestamp
。此代码:
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println("sqlDate equals utilDate:\t" + sqlDate.equals(utilDate));
System.out.println("utilDate equals sqlDate:\t" + utilDate.equals(sqlDate));
java.sql.Time time = new java.sql.Time(utilDate.getTime());
System.out.println("time equals utilDate:\t\t" + time.equals(utilDate));
System.out.println("utilDate equals time:\t\t" + utilDate.equals(time));
java.sql.Timestamp timestamp = new java.sql.Timestamp(utilDate.getTime());
System.out.println("timestamp equals utilDate:\t" + timestamp.equals(utilDate));
System.out.println("utilDate equals timestamp:\t" + utilDate.equals(timestamp));
结果如下:
sqlDate equals utilDate: true
utilDate equals sqlDate: true
time equals utilDate: true
utilDate equals time: true
timestamp equals utilDate: false
utilDate equals timestamp: true
因为(而不是key.equals(parameter)
),在给定的情况下会出现这个奇怪的结果
那么,如何避免这种情况呢
1) 在映射中使用Long
键,而不是Date
(正如Mureinik所指出的)-因为java.util.Date
和java.util.Timestamp
从getTime()
返回相同的值,所以无论使用哪个实现,键都应该是相同的。这似乎是最简单的方法
2) 在地图中使用日期对象之前,将其标准化。这种方法需要做更多的工作,但对我来说似乎更可取,因为它更清楚地图是什么——一堆Foo
,每一个都存储在某个时刻。这就是我最终使用的方法,使用以下方法:
public Date getStandardizedDate(Date date) {
return new Date(date.getTime());
}
这需要一个额外的方法调用(这是一个很荒谬的调用),但对我来说,涉及映射的代码可读性的提高是值得的。第1部分:“难道equals
不应该与compareTo
一致吗?”*
不,compareTo应该与equals一致,但相反的是无关紧要的
P>RealReto是排序顺序。等值是相等的。考虑赛车,在实践中可以用最快的圈时间来排序,以确定起始位置。相同的圈数并不意味着它们是同一辆车。< /P>
第2部分:平等日期
数据库调用将返回java.sql.Date,尽管它可以分配给java.util.Dare,因为它扩展了java.util.Dare,但它不会相等,因为类是不同的
解决方法可能是:
java.util.Date test;
java.sql.Date date;
if (date.equals(new java.sql.Date(test.getTime()))
我也这么认为,但它在Java 8上似乎工作得很好。Java.util.Date
检查instanceof Date
,这Java.sql.Date
是什么。您的数据库返回什么Date
实现?噢,有趣的是:keyDate.getClass()=class Java.util.Date,但effDate.getClass()=类java.sql.Timestamp.Ah,好了,就这样。Timestamp
是Date
,但是Date
不是Timestamp
(它似乎有自己的实现)。哇,这是janky:对于这一点,我建议看一看Joshua Bloch写的有效java,他在那里讨论了equals()
和compareTo()
非常详细。他提到了以下内容:@torngat约书亚提到了什么?:)