【问题标题】:Why does java.sql.Timestamp extend java.util.Date为什么 java.sql.Timestamp 扩展 java.util.Date
【发布时间】:2018-06-13 00:55:45
【问题描述】:

当我看到这个时,我感到困惑:

  public class Timestamp extends java.util.Date {
    //...
    public boolean equals(java.lang.Object ts) {
      if (ts instanceof Timestamp) {
        return this.equals((Timestamp)ts);
      } else {
        return false;
      }
    }
    public int hashCode() {
        return super.hashCode();
    }

确实用粗体记录了<strong>Note</strong> (见https://docs.oracle.com/javase/7/docs/api/java/sql/Timestamp.html

对我来说,做出这样一个非常糟糕的决定的原因是什么? 与 java.util.Date 对象进行比较时,为什么不调用 super.equals(this) 以使相等比较对称?

【问题讨论】:

  • 因为当时做出了错误的决定。
  • 这是一个非常古老的api。它利用了当时可用的东西
  • 如果Date.equals() 认为日期不等于Date 子类的实例,则正确的解决方案是。但是当他们在 JDK 1.1 中添加 java.sql 包时,他们不敢在 Date 类中进行这种更改,因为这从 JDK 1.0 就已经存在了。
  • 好消息是您不必在意。如今,您可以将java.time.Instantjava.time.LocalDateTime 对象存储到SQL 数据库的时间戳列中,并再次将它们作为相同类型检索。您根本不需要使用旧的 java.sql.Timestamp 类。
  • 投反对票的人:三思而后行,并在投票的同时发表评论。此问题有效,并表现出深思熟虑的好奇心。这个类继承确实是一个糟糕的设计,一个有缺陷的hack,值得探究的人讨论。

标签: java timestamp java.util.date datetime-comparison


【解决方案1】:

改为使用 java.time

正如其他人所说:

  • 这个类继承是糟糕的设计,一个有缺陷的 hack。
  • 现在没有实际意义,因为这个类现在是遗留的,被 java.time.Instant 取代。

避免在 java.time 包之外找到所有旧的旧日期时间类。

对于数据库,使用符合JDBC 4.2 or later 的驱动程序直接与您的数据库交换 java.time 对象。你可以忘记所有关于java.sql.Timestamp 的事情。

存储:

Instant instant = Instant.now() ;
myPreparedStatement.setObject( … , instant ) ;

检索:

Instant instant = myResultSet.getObject( … , Instant.class ) ;

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

从哪里获得 java.time 类?

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

  • 我希望这个决定至少在实施 Timestamp 时是有意义的。但如果每个人都同意这只是一个缺陷,那就这样吧。你的答案是更有说服力的一个。不确定我们是否可以(想要)添加您提到的这个反向移植,因为我们正试图从这个 java 版本迁移出去。无论如何,很好的答案。谢谢。
  • @estani 后端口项目由与 java.time JSR 310 项目相同的人 Stephen Colebourne 领导。反向端口被设计为与 java.time 前向兼容,使用相同的类和方法名。当您从使用反向端口转移到内置类时,您只需更改 import 语句即可。何必?因为遗留的日期时间类真的很糟糕,一团糟。
【解决方案2】:

Date.equals 需要Dates,所以super.equals 不可行。 Timestamp.equalsequals(Timestamp ts) 重载,因此也遵守平等契约,需要 Timestamps。

重载有点过度设计;但我见过更糟糕的设计。

Timestamp 的 nanos 可能是新时间 API 的新增功能,在旧 Date 中不可用。

考虑到新的时间 API 可能会在很远的将来取代这个类,我认为没有任何更改请求的理由。 (SQL 时间类现在有点多余。)


Timestamp#equals(Object)
    checks for both to be a Timestamp (as by contract)
    calls Timestamp#equals(Timestamp)

Timestamp#equals(Timestamp)
    calls Date#equals
    and then also compares the extra nanos fields

我所说的“不可行”是指没有比较两个对象的所有方面。

【讨论】:

  • 我无法理解您的回答 Date.equals(Timestamp) 非常好,并且会将对象比较到纳秒级。如果非 Timestamp 对象为 /* else */ return other.equals(this);,则可以实现时间戳,并且它会再次对称。
  • 是的,我表达得不够好:可以调用date.equals(timestamp),但不能调用timestamp.equals(date),因为它需要将timestamp 减少到一个日期。这是一个关于平等的决定,更倾向于不对称:一架飞机和一辆昂贵的老古董在扩展一辆带有劳斯莱斯发动机实例的机动车辆时是不相等的。
  • “Timestamp 的 nanos 可能是从新的 time API 中添加的”,这是一个错误的说法,因为这个特性(以及整个 Timestamp 类)从 Java 开始就已经存在了。许多数据库具有标称的纳秒精度,因此从一开始就引入了 nanos 来支持这一点。
【解决方案3】:

做出这样一个对我来说非常糟糕的决定的原因是什么?与 java.util.Date 对象进行比较时,为什么不调用 super.equals(this) 以使相等比较对称?

原因可能只有作者知道,没有记录。但是 super.equals(this) 也不会尊重 equals 的契约。由于 Date 错过了纳秒精度,唯一的方法就是把纳秒排除在外。但这会导致两个不相等的 Timestamp 实例(具有不同的 nano 值)都等于同一个 Date 实例的情况,这意味着实现不具有传递性。

【讨论】:

  • 好吧...如果 nano == 0 就不行吗? :-) 这正是我的情况……作为一种变通方法,我保证将 Date 对象与 Timestamp 对象进行比较。
  • 如果 nano == 0,为什么还要费心使用 Timestamp?只需使用 Date 并完全避免问题:)
  • 这是 jpa 的东西。 Hibernate(在我们使用的版本中)将 Date 映射到 Postgres 的 Timestamp。从代码中看不到这一点,您必须调试才能看到实际发生的情况。
  • 不知道您使用的是哪个版本,但可能可以告诉 JPA 将其映射到日期。通过使用不同的注释或使用属性类型转换器。 Stackoverflow 上有很多关于该主题的帖子。
猜你喜欢
  • 1970-01-01
  • 2012-05-24
  • 2011-08-17
  • 2017-10-08
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多