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约书亚提到了什么?:)