【问题标题】:What is this weird dynamic method dispatch behavior inside a static method in Java [duplicate]Java中静态方法中这种奇怪的动态方法调度行为是什么[重复]
【发布时间】:2016-08-24 01:04:12
【问题描述】:

以下示例中的实用程序方法仅用于说明目的。

在下面的示例中,instance method 调用被调度到引用类型而不是运行时对象。

import java.sql.Timestamp;
import java.util.Date;
public class DynamicMethodDispatchEx {

    public static void main(String[] args) {
        Timestamp now = new Timestamp(System.currentTimeMillis());
        Timestamp beforeNow = new Timestamp(now.getTime() - 1);

        System.out.println("Finding newest in " + now + " and " + beforeNow);
        System.out.println("Attempt 1: " + staticFindNewer(beforeNow, now));
        System.out.println("Attempt 2: " + staticFindNewer(now, beforeNow));

    }

    public static Date staticFindNewer(Date one, Date two) {
        if (one.after(two)) {
            return one;
        } else {
            return two;
        }
    }

}

下面是我得到的输出

Finding newest in 2016-08-23 17:56:36.375 and 2016-08-23 17:56:36.374
Attempt 1: 2016-08-23 17:56:36.375
Attempt 2: 2016-08-23 17:56:36.374 // <---

经过一番调查,我发现staticFindNewer() 中调用了java.util.Date.after(Date),而尝试1 和2 的差异是由于使用Date 的方法导致精度损失。

但是,我对动态调度感到困惑。 我希望Timestamp#after(Timestamp) 被调用,但Date#after(Date) 被调用。我认为实例方法调度总是基于运行时对象。我是否错过了一些愚蠢的事情(很可能)?

【问题讨论】:

  • 我不明白你的问题。你有什么困惑?假设你指的是java.sql.Timestamp,那是java.util.Date的子类型
  • @SotiriosDelimanolis 我期待 one.after(two) 被发送到 java.sql.Timestamp 但它被发送到 java.util.Date
  • 您的意思是您希望调用Timestamp#after(Timestamp) 而不是Date#after(Date)?请将其编辑到您的问题中。
  • @SotiriosDelimanolis 更新了问题。谢谢。
  • 两个对象都是Timestamp 对象 - 但是方法的参数类型是在编译时确定的。在这种情况下,您的静态方法接受Date,因此它使用它。

标签: java dynamic-dispatch


【解决方案1】:

我希望 Timestamp#after(Timestamp) 被调用,但 Date#after(Date) 被调用。我认为实例方法调度总是基于运行时对象。

动态调度只发生在被调用的对象上,而不是在参数上。

所以调用会转到Timestamp#after(Date)(因为参数的编译时类型是Date,而被调用者的运行时类型是Timestamp)。

不幸的是,Timestamp 并没有覆盖这个方法,所以它默认回到Date#after(Date)(这里不太好用)。

因此,您必须确保直接调用Timestamp#after(Timestamp),或者改用Date#compareTo(Date) 方法,该方法已正确实现(并在Timestamp 中被覆盖)。

【讨论】:

  • 谢谢。这说明了这个问题。但是没有java.sql.Timestamp#after(Date date)
  • 我以为它就在那里。我将它与Timestamp#compareTo(Date)(已正确实现)混淆了。想知道为什么after 不只是发送到compareTo...
猜你喜欢
  • 2011-12-11
  • 2011-03-12
  • 1970-01-01
  • 2011-01-03
  • 1970-01-01
  • 1970-01-01
  • 2015-08-06
  • 1970-01-01
相关资源
最近更新 更多