Skip to content

Latest commit

 

History

History
69 lines (49 loc) · 2.01 KB

e93f.md

File metadata and controls

69 lines (49 loc) · 2.01 KB

Back to questions

Solution to e93f: Apparent and actual types

See code at solutions/code/tutorialquestions/questione93f

The accept method in D does not override the accept method in C. The reason is that accept in C has a parameter of type A, while accept in D has a parameter of type B.

As a result, accept in D overloads accept in C. That is, an object of type D has two distinct methods called accept:

public void accept(A a) { ... } // (1) inherited from C

public void accept(B b) { ... } // (2) added in D

If we call accept on an object reference with apparent type D, the Java compiler will choose one of the above methods: the method with the most specific applicable type. So, for example, if we write:

D d = new D();
A a = new A();
d.accept(a);

method (1) will be called, whereas if we write:

D d = new D();
B b = new B();
d.accept(b);

then method (2) will be called, because although b has type A and type B, B is more specific.

Things get more tricky when references have different actual vs.~apparent types. For example, in this case:

C d = new D();
B b = new B();
d.accept(b);

method (1) will be called! This is because overloading is resolved by the compiler using apparent types. At the call site, d.accept(b), d has apparent type C, thus the accept method of C is selected. Variable b is an acceptable argument for this version of accept, since b has type A (because it has type B, which is a subclass of A).

Similarly, in this case:

D d = new D();
A b = new B();
d.accept(b);

method (1) will also be called! Here the compiler knows that d's apparent type is D, so there are two choices for accept. The choice is decided based on the apparent type of argument b, which is A.

From this discussion, it should be clear that the main method given in the question will print:

Accepted an object of type A.
Accepted an object of type B.