Why is the wrong method called: Strange inheritance behaviour

So this question is about inheritance and method overriding. Specifically: the case when a child class has a same-name method as the parent, but with a different signature, like:

class A has methodX(String arg)
class B extends A has methodX(int arg)

In normal cases the correct method will be called based on the argument.

But in the following code I've encountered some strange behavior which I can't really explain:

static class A {
    public void method1() {
        System.out.println("m1.A");
    }
    public void method4(A arg) {        //Original method4
        System.out.println("m4.A");
    }
}

static class B extends A {
    public void method1() {
        System.out.println("m1.B");
    }
}

static class C extends B {
    public void method4(A arg) {        //Override method4 from Class A
        System.out.println("m4.C");
    }
}

static class E extends C {
    public void method1() {
        System.out.println("m1.E");
    }
    public void method4(E arg) {        //NO OVERRIDE: Same name, but different method4 than in class A or C
        System.out.println("m4.E");
    }
}


public static void main(String[] args) {
    A va = new A();
    B vb = new B();
    C vc = new C();
    E ve = new E();

    //At this point everything is fine
    ve.method4(ve);  //Calls method4 from class E based on parameter type - CORRECT
    ve.method4(va);  //Calls method4 from class C based on parameter type - CORRECT

    //After this code strange things happen
    vc = new E();
    vb = vc;

    vb.method1();    //Output: m1.E; method1 from class E is called - CORRECT
    vb.method4(vb);  //Output: m4.C; method4 from class C is called - why?

    vc.method1();    //Output: m1.E; method1 from class E is called - CORRECT
    vc.method4(vc);  //Output: m4.C; method4 from class C is called - why?
    vc.method4(ve);  //Output: m4.C; method4 from class C is called - why?

}

So the output of the programm above is:

m4.E
m4.C

m1.E
m4.C  //why? Expected: m4.E

m1.E
m4.C  //why? Expected: m4.E
m4.C  //why? Expected: m4.E

The behaviour of

vb and vc

is what i cannot understand. Any ideas?

Jon Skeet
people
quotationmark

I'm guessing that you expected m4.E to be printed. But don't forget that overload resolution is performed at compile-time, not at execution time.

Neither C nor B have a method4(E) method available, so the compiler resolves the calls to the method4(A) method... which isn't overridden by E. All the calls you have m4.C // why? in the question are calls to a method with signature method4(A), called on an instance of E. Now E doesn't override method4(A), so it's left with the implementation in C, which prints m4.C.

Nothing strange going on here at all.

people

See more on this question at Stackoverflow