khalidbouklouf
khalidbouklouf

Reputation: 85

Need help on a polymorphism matter

I have a simple code, I want to know why and how some methods are chosen over the others :

class A :

public class A {
    int f(A aa){
        return 1;
    }
}

class B :

public class B extends A {
    int f(A aa){
        return 2;
    }

    int f(B bb){
        return 3;
    }
}

Test :

public class Test {
    public static void main(String[] args) {
        A a = new A();
        A ab = new B();
        B b = new B();

        System.out.println(a.f(a));
        System.out.println(a.f(ab));
        System.out.println(a.f(b));

        System.out.println(ab.f(a));
        System.out.println(ab.f(ab));
        System.out.println(ab.f(b));

        System.out.println(b.f(a));
        System.out.println(b.f(ab));
        System.out.println(b.f(b));
    }
}

Now, the output of this program is as below :

1
1
1
2
2
2
2
2
3

Now, can you please tell me why System.out.println(ab.f(b)) gave 2 as output ?

Upvotes: 3

Views: 69

Answers (3)

RealSkeptic
RealSkeptic

Reputation: 34628

Overload resolution is done at compile time. Overrides are used at runtime.

This means that at compile time, the compiler decides which of all the method signatures is appropriate for the method invocation. Then, at runtime, if that method with that signature is overridden in the run-time object being used, the overridden method is used.

At compile time, only the static type of the variable is known. That is, only method signatures that are associated with the declared type of the variable are considered.

In this case, the variable ab is declared to be A. Therefore, only method signatures that exist in A are considered for the call ab.f(b). The only f in type A is the f(A aa) method. The call is legal for this method signature, so the code generated by the compiler says "at this point, call the method f that has a single parameter of type A, and pass b as the parameter to it."

When runtime comes, since ab is actually a B instance, the method f that has a single parameter of type A is actually overridden in it, so it will print 2, rather than 1.

Contrast this with b.f(b). Here the declared type of the variable b is B. Therefore it has two overloads of the method f - one with a B parameter and one with an A. At compile time, it already knows that the argument b is declared B. So the most specific overload is f(B bb). The invocation is translated into "call the f with a single parameter of type B". And at runtime, this prints 3.

The difference? At compile time, ab was of type A and f(B bb) doesn't exist in that type. b was of type B, and f(B bb) exists and is the most specific overload.

Upvotes: 2

Amit
Amit

Reputation: 46323

ab is an instance of class B, as such, it overrides int f(A aa) to return 2.

The reason f(A aa) is executed, and not f(B bb) is that ab is a variable of type A. As such, there is no f(B bb) available to be called so f(A aa) is matched (b of type B inherits A).

Although the value of ab is indeed an object of type B, the compiler can't assume that, and certainly can't call functions that don't exist for the declared type of the variable.

Upvotes: 0

Noam Mansur
Noam Mansur

Reputation: 362

ab is a static variable of class A. while initializing as a dynamic instance of B, the method f in class A is overridden.

Now when calling ab.f(b) it "goes" to class A (to the static value) and looks for f ,which now returns 2.

Upvotes: 0

Related Questions