Take a close look at where doStuff() is defined in Concrete. It is not a method of Concrete, but a method of an anonymous class stuffed into the static variable a. Now note that variable a has been redeclared in Concrete, so it is not the one declared in Abs (that one is hidden). Now when main() is executed, it invokes doStuff() on its copy of variable a, which contains an instance of Concrete. Since Concrete has no method doStuff() declared, it uses the one inherited from Abs. Hence the output.
Thanks Steve, but I think what's going on is the following: main() gets inherited from Abs, therefore, it'll operate on the fields from the Abs class. Then, doStuff() is not overridden, it's again a simple inheritance, so polymorphism is not applicable. The overall picture is that inherited main() of Concrete calls inherited doStuff() to produce the output of E. However, if you place main() in Concrete, the answer will be StackOverflowError.
Regardless whether you run Abs or Concrete, you will get the same output, i.e.
The important thing to remember is that the variable a in main() is statically bound during compilation. So no matter where you call main()(Abs or Concrete), it will still use that variable defined in Abs. However, the call to doStuff() in the main() method is dynamic. So, during run time, the VM will still have to resolve the object pointed to by a, which in this case is the instance of Concrete. Now since the class Concrete doesn't have any method called doStuff(), Java will invoke the one inherited from Abs. Notice that if you define a doStuff() method in Concrete, it will call that method:
If you move the main() method to the Concrete class, then the variable a in Concrete will be statically bounded to main(). But still, the call to doStuff() will still be dynamic. And the doStuff() method it will call is the one defined in the anonymous class, because that is where the variable a is pointing to. But in this case, you will get a 'StackOverflow error' because the anonymous class' doStuff() is calling itself(because of this.doStuff). [ September 20, 2003: Message edited by: Alton Hernandez ]
Originally posted by Vad Fogel: Alton, thanks for this good explanation. The only confusing thing for me here is how early binding which is static a variable mapping still allows for polymorphic call to doStuff() method.
Hi Vad, Variables are never polymorphic, but the calls to instance methods are:
I think it may be valid to say something like: it's what's on the right side of the dot that determines early or late binding. So in a.doStuff() it doesn't matter whether a is static or instance, only whether doStuff() is static or instance; being the latter, you get late binding.