views:

118

answers:

3

Hello,

For the following code why does it print A, B? I would expect it to print B, B. Also, does the method call performed by the JVM is evaluated dynamically or statically?

public class Main {
    class A {

    }

    class B extends A {

    }

    public void call(A a) {
        System.out.println("I'm A");
    }

    public void call(B a) {
        System.out.println("I'm B");
    }


    public static void main(String[] args) {

        Main m = new Main();
        m.runTest();
    }

    void runTest() {
        A a = new B();
        B b = new B();

        call(a);
        call(b);
    }

}
+9  A: 

Overloading is determined statically by the compiler. Overriding is done at execution time, but that isn't a factor here.

The static type of a is A, so the first method call is resolved to call(A a).

Jon Skeet
Thank you, so what is evaluated dynamically?
Maxim Veksler
@Maxim Veksler: Overriding - that is determined by the *actual* type of the target object, rather than the compile-time type.
Jon Skeet
Thank you very much Jon.
Maxim Veksler
+2  A: 

Since your object is known by its type A at that moment, the method with argument A is invoked. So yes, it's determined statically.

That's in order to avoid ambiguities. Your B is also an A - but both methods can't be invoked at the same time.

Bozho
+1  A: 

B is a subclass of A. Since you instanciate a B, but assign it to a variable typed A, all B specifics will be 'lost', hence call(a) will be dispatched to call(A, a) and print 'A'.

The MYYN
That's a bit misleading. The object called `a` still retains "all of its `B` specifics" - calling `a.getClass().getSimpleName()` for example would return "B". It's just that as Jon pointed out, the overload is determined by the type of the **reference**, at compile time. The compiler doesn't "know" in this context that `a` is actually an instance of `B`, so it compiles the call to the `call(A a)` method. But `a` still *is* an instance of `B`.
Andrzej Doyle