Java 中静态方法内部的这种奇怪的动态方法调度行为是什么

What is this weird dynamic method dispatch behavior inside a static method in Java

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

在下面的示例中,instance method 调用被分派给引用类型,但没有分派给 运行-time 对象。

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 // <---

经过一些调查,我发现 java.util.Date.after(Date)staticFindNewer() 中被调用,并且尝试 1 和 2 中的差异是由于使用 Date 的方法造成的精度损失。

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

I expected Timestamp#after(Timestamp) to be invoked but Date#after(Date) was getting invoked. I thought the instance-method dispatch was always based on runtime object.

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

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

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

所以你必须确保直接调用 Timestamp#after(Timestamp),或者使用正确实现的 Date#compareTo(Date) 方法(并在 Timestamp 中覆盖)。