I am looking for an explanation for the following behavior:
Here are the classes:
package a;
public class A {
void m() { System.out.println("A"); }
}
// ------
package b;
import a.A;
public class B extends A {
void m() { System.out.println("B"); }
}
// ------
package c;
import b.B;
public class C extends B {
void m() { System.out.println("C"); }
}
// ------
package a;
import c.C;
public class D extends C {
void m() { System.out.println("D"); }
}
// ------
package b;
import a.D;
public class E extends D {
void m() { System.out.println("E"); }
}
// ------
package c;
import b.E;
public class F extends E {
void m() { System.out.println("F"); }
}
The Main class is in package a
:
package a;
import b.B;
import b.E;
import c.C;
import c.F;
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
C c = new C();
D d = new D();
E e = new E();
F f = new F();
System.out.println("((A)a).m();"); ((A)a).m();
System.out.println("((A)b).m();"); ((A)b).m();
System.out.println("((A)c).m();"); ((A)c).m();
System.out.println("((A)d).m();"); ((A)d).m();
System.out.println("((A)e).m();"); ((A)e).m();
System.out.println("((A)f).m();"); ((A)f).m();
System.out.println("((D)d).m();"); ((D)d).m();
System.out.println("((D)e).m();"); ((D)e).m();
System.out.println("((D)f).m();"); ((D)f).m();
}
}
And here is the output:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
((A)d).m();
D
((A)e).m();
E
((A)f).m();
F
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
And here are my questions:
1) I understand that D.m()
hides A.m()
, but a cast to A
should expose the hidden m()
method, is that true? Or is D.m()
overrides A.m()
in spite of the fact that B.m()
and C.m()
breaks the inheritance chain?
((A)d).m();
D
2) Even worse, the following code shows overriding in effect, why?
((A)e).m();
E
((A)f).m();
F
And why not in this part:
((A)a).m();
A
((A)b).m();
A
((A)c).m();
A
and this one?
((D)d).m();
D
((D)e).m();
D
((D)f).m();
D
I am using OpenJDK javac 11.0.2.
EDIT: The first question is answered by How to override a method with default (package) visibility scope?
An instance method mD declared in or inherited by class D, overrides from D another method mA declared in class A, iff all of the following are true:
- A is a superclass of D.
- D does not inherit mA (because crossing package boundaries)
- The signature of mD is a subsignature (§8.4.2) of the signature of mA.
- One of the following is true: [...]
- mA is declared with package access in the same package as D (this case), and either D declares mD or mA is a member of the direct superclass of D. [...]
BUT: the second question is still unresolved.
From the Java Documentation, "[package visibility] indicates whether classes in the same package as the class (regardless of their parentage) have access to the member." In this example from javax. swing , package javax.
In Java, it is possible to inherit attributes and methods from one class to another. We group the "inheritance concept" into two categories: subclass (child) - the class that inherits from another class. superclass (parent) - the class being inherited from.
In other words, a default member may be accessed only if the class accessing the member belongs to the same package, whereas a protected member can be accessed (through inheritance) by a subclass even if the subclass is in a different package.
Yes, they can always inherit the protected members of its superclass regardless of the package they are in.
I understand that
D.m()
hidesA.m()
, but a cast toA
should expose the hiddenm()
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()
overridesA.m()
in spite of the fact thatB.m()
andC.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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With