1

The utility method in the below example is for illustration purposes only.

In the example below, instance method invocation was dispatched to reference type but not to the run-time object.

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;
        }
    }

}

The below was the output I got

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

After some investigation, I found out that java.util.Date.after(Date) was being invoked in the staticFindNewer() and the discrepancy in attempt 1 and 2 and was due to precision loss as Date's methods were being used.

However, I'm puzzled about dynamic dispatch. 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. Am I missing something silly (most probably)?

phanin
  • 5,327
  • 5
  • 32
  • 50
  • I don't understand your question. What are you confused about? Assuming you're referring to `java.sql.Timestamp`, that's a subtype of `java.util.Date` – Sotirios Delimanolis Aug 24 '16 at 01:08
  • @SotiriosDelimanolis I was expecting `one.after(two)` to be dispatched to java.sql.Timestamp but it was dispatched to `java.util.Date` – phanin Aug 24 '16 at 01:09
  • 2
    You mean you expected `Timestamp#after(Timestamp)` to be invoked instead of `Date#after(Date)`? Please edit that into your question. – Sotirios Delimanolis Aug 24 '16 at 01:10
  • @SotiriosDelimanolis Updated question. Thanks. – phanin Aug 24 '16 at 01:15
  • Both objects are `Timestamp` objects - But the argument type to the method is determined at compile time. In this case, your static method takes in a `Date` so it uses that. – Krease Aug 24 '16 at 01:19
  • Wow, nice find @SotiriosDelimanolis. – shmosel Aug 24 '16 at 01:24
  • @shmosel "Timestamp after overload". I've been around long enough to remember some of these more exotic posts. – Sotirios Delimanolis Aug 24 '16 at 01:25
  • Some more discussion here: http://stackoverflow.com/questions/8929242/compare-date-object-with-a-timestamp-in-java I suppose the lesson is to avoid the old date/time API and go with `java.time` as much as you can. – Thilo Aug 24 '16 at 01:28

1 Answers1

1

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.

Dynamic dispatch happens only on the invoked object, not on the arguments.

So the call would go to Timestamp#after(Date) (because the compile-time type of the argument is Date, and the runtime type of the callee is Timestamp).

Unfortunately, Timestamp does not override this method, so it defaults back to Date#after(Date) (which does not work too well here).

So you have to make sure you call Timestamp#after(Timestamp) directly, or use the Date#compareTo(Date) method instead, which is properly implemented (and overridden in Timestamp).

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • 1
    Thanks. This sheds light on the issue. But there's no `java.sql.Timestamp#after(Date date)`. – phanin Aug 24 '16 at 01:21
  • I thought it was there. I confused it with `Timestamp#compareTo(Date)` (which is properly implemented). Wonder why `after` is not just dispatching to `compareTo`... – Thilo Aug 24 '16 at 01:24