Can't seem to understand complex polymorphism

Ron Kantor :

I'm studying CS and we have questions about polymorphism that I cant wrap my mind around. Here is an example:

public class AA{
    public AA(){
        foo();
    }
    private void foo() {
        System.out.print("AA::foo ");
        goo();
    }
    public void goo(){
        System.out.print("AA::goo ");
    }
}

public class BB extends AA{
    public BB(){
        foo();
    }
    public void foo(){
        System.out.print("BB:foo ");
    }
    public void goo(){
        System.out.print("BB::goo ");
    }
    public static void main(String[] args){
        // Code goes here
    }
}

When in void main i add the line:

AA a = new BB();

it goes first AA constructor prints AA:foo but then goo() sends it to BB's goo, why so?

Simple polymorphism such as "Animal -> cat/spider/dog" is easy to understand but when it comes to this I'm just lost. Can you guys give me any tips how to read this code? What are the rules are?

EDIT: there is no @Override annotation because this is a question from an exam.

Andrew Tobilko :

Explanation

public class AA {

    private void foo() { ... }
    ^^^^^^^

}

Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:

A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:

  • m is a member of the direct superclass of C.
  • m is public, protected, or declared with package access in the same package as C.
  • No method declared in C has a signature that is a subsignature of the signature of m.

Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding

Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.

But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.


It's a bit tricky, so I would recommend you put the @Override annotation everywhere it's supposed to be.

public class BB extends AA {

    @Override   // it doesn't compile - no overriding here
    public void foo() { ... }
    @Override   // it does override
    public void goo() { ... }

}

It also might be helpful to detect another problem:

Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.

If a method declaration in type T is annotated with @Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.

Java Language Specification - 9.6.4.4. @Override

Illustration

If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.

Java Language Specification - 8.8.7. Constructor Body

To put it simply,

public BB() {
    foo();
}

turns into

public BB() {
    super();
    foo();
}

Keeping super(); in mind, we can make the next illustration:

new BB()
        AA()                       // super(); -> AA constructor
                A#foo()            // private method call 
                        B#goo()    // polymorphic method call
        BB()                       // BB constructor
                B#foo()            // plain method call 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=430817&siteId=1