java.util.Date equals()似乎没有按预期工作
问题
我有一个Map< Date,Foo>和一个来自数据库的对象列表,其中包含一个有效的属性,我想查看我的地图中的Date键是否等于数据库中的任何有效日期 – 如果是用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,即使我确定它有时在那里. 调查 作为一个理智检查,我打印出了很长的日期值,以及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: %dn"; 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)The
…看起来getTime方法为这两个日期返回相同的long值,但相等则返回false.有什么想法可能会发生吗?我搜索过高低,但我还没有发现任何人描述同样的问题. 附:我被卡住了使用java.util.Date.请不要只推荐JodaTime. P.P.S.我意识到我可以改变这个代码的结构,并且可能会使它工作.但这应该是有效的,我不想只是解决它,除非是一个已知的问题或事情.这似乎是错误的 解决方法
正如
Mureinik所暗示的那样,Sotirios Delimanolis更具体地指出,这里的问题是与java.util.Date的实现.
java.util.Date在java.sql包中扩展了3个类,所有这些都似乎做了类似的事情,在java中的区别并不清楚(似乎它们存在的原因只是使java类更精确地对齐SQL数据类型) – 有关其差异的更多信息,请查看this very detailed answer. 现在,在看起来像是一个严重的设计缺陷,有人决定使 我写了几行,看看哪些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:tt" + time.equals(utilDate)); System.out.println("utilDate equals time:tt" + 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 自从 那么,如何解决呢? 1)在地图中使用长键,而不是一个Date(如Mureinik所说) – 由于java.util.Date和java.util.Timestamp从getTime()返回相同的值,所以你应该执行哪个实现使用,关键将是一样的.这样做似乎是最简单的. 2)在地图中使用之前对日期对象进行标准化.这样做需要更多的工作,但是对我来说似乎更可取,因为它更清楚地图是什么 – 一堆Foo每次存储在一段时间.这是我最后使用的方式,使用以下方法: public Date getStandardizedDate(Date date) { return new Date(date.getTime()); } 它需要一个额外的方法调用(和那种可笑的方法),但对我来说,涉及Map< Date,Foo>的代码的可读性增加了是值得的 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |