Inheritance at package visibility in Java

I understand that D.m() hides A.m(), but a cast to A should expose the hidden m() method, is that true?

There is no such thing as hiding for instance (non-static) methods. Here, it's an example of shadowing. A cast to A in most places just helps to resolve the ambiguity (e.g. c.m() as is can refer to both A#m and C#m [which isn't accessible from a]) that otherwise would lead to a compilation error.

Or is D.m() overrides A.m() in spite of the fact that B.m() and C.m() breaks the inheritance chain?

b.m() is an ambiguous call because both A#m and B#m are applicable if you set the visibility factor aside. The same goes for c.m(). ((A)b).m() and ((A)c).m() clearly refer to A#m which is accessible for the caller.

((A)d).m() is more interesting: both A and D reside in the same package (thus, accessible [which is different from the two above cases]) and D indirectly inherits A. During dynamic dispatch, Java will be able to call D#m because D#m actually overrides A#m and there is no reason not to call it (despite the mess going on the inheritance path [remember that neither B#m nor C#m overrides A#m due to the visibility issue]).

Even worse, the following code shows overriding in effect, why?

I can't explain this because it's not the behaviour I expected.

I dare say that the result of

((A)e).m();
((A)f).m();

should be identical to the result of

((D)e).m();
((D)f).m();

which is

D
D

since there is no way to access the package-private methods in b and c from a.


Interesting question. I checked that in Oracle JDK 13 and Open JDK 13. Both give the same result, exactly as you wrote. But this result contradicts with Java Language Specification.

Unlike class D, which is in the same package as A, classes B, C, E, F are in a different package and because of package private declaration of A.m() cannot see it and cannot override it. For classes B and C it works as specified in JLS. But for classes E and F it doesn't. The cases with ((A)e).m() and ((A)f).m() are bugs in the implementation of Java compiler.

How should work ((A)e).m() and ((A)f).m()? Since D.m() overrides A.m(), this should hold also for all their subclasses. Thus both ((A)e).m() and ((A)f).m() should be the same as ((D)e).m() and ((D)f).m(), means they all should call D.m().