How far do Java's polymorphism and dynamic method dispatch go?
Not far enough, IMO.

A long time ago, early in my Java-life, I made an impromptu, informal bet with a couple of fellow programmers about Java's level of dynamicity (is that a word?). The question was this: Does Java use the assigned type or the declared type of variables used as method arguments when doing method lookup?
OK, that's an obscure enough sounding question - it's also difficult to follow. Let me back up a bit...
We know that Java will use the assigned type of a variable to dynamically lookup the proper implementation of a method to invoke; that's part of polymorphism. It does this regardless of the declared reference type. This code snippet shows an example of what I'm talking about:

Object anObject = new Foo();
// Foo.toString(), if it exists, gets invoked
// at runtime -> dynamic lookup.

This is called late binding, because it occurs as late as possible in the life of the object. I was wondering if Java behaves similarly when considering method arguments. In other words, is method lookup done dynamically (at runtime) with respect to method arguments, or is it done statically at compile-time? My experiments surprised me at the time, and it turns out the bet was a push.
Let's take the following classes:

class Superclass {}
class Subclass extends Superclass {}
class Test {
	public void aMethod(Superclass s) {...}
	public void aMethod(Subclass s) {...}

...what are the results of each of the following calls to aMethod()?

	Test aTest = new Test();
	Superclass aSuper = new Superclass();
	Subclass aSub = new Subclass();

test.aMethod(aSuper); // 1 test.aMethod(aSub); // 2
aSuper = aSub; test.aMethod(aSuper); // 3
aSuper = new Subclass(); test.aMethod(aSuper); // 4
test.aMethod((Subclass)aSuper); // 5
aSuper = null; test.aMethod(aSuper); // 6
test.aMethod(null); // 7

As it turns out, only numbers 1, 2, 5, and 6 do the method lookup like I expected. #3 and #4 both invoke aMethod(Superclass) even though the object being passed in is (at runtime) a Subclass. Most interestingly, #7 invokes aMethod(Subclass), apparently because the compiler goes to the version that takes the narrowest argument type it can find (based on some further experimentation I performed).

All photographs and content is copyright © 2003-2006 Eric Rizzo & Jazmine Rizzo

contact classes office hours about me Go home