The specification of when a method of a subclass overrides a method
in a superclass originally given in JLS 8.4.6.1 states:
8.4.6.1 Overriding (By Instance Methods)
If a class declares an instance method, then the declaration of that
method is said to override any and all methods with the same signature
in the superclasses and superinterfaces of the class that would otherwise
be accessible to code in the class.
This definition needed to be corrected, because it implies that method override is non-transitive. Consider the following example:
package P1;
class A {
void m(){System.out.println("A.m");}
public void callM(){ m();}
}
public class B extends A {
protected void m() { System.out.println("B.m");}
}
package P2;
class C extends P1.B {
protected void m(){ System.out.println("C.m");}
public static void main(String[] args) {
C c = new C();
c.callM();
}
Given the original definition of override, we find that the method m() declared in C overrides the method m() declared in B(), since it has the same name and signature and is accessible from class C. However, we also find that the method m() declared in C does not override the method m() declared in A(), since it is private to package P1 and therefore not accessible from class C.
In this case, invoking callM() on an instance of C causes a call of m() where the target of the method invocation is an instance of C as well. However, this call is in the class P1.A, and is attempting to invoke a package private method of A. Since this method is not overridden by C, the code will not print "C.m" as expected. Instead, it prints "B.m".
This is quite unintuitive, and also incompatible with the behavior of the classic VM.
We believe that this interpretation, while literally accurate, is undesirable. It prevents a package private method from ever being overridden outside its package, even if a subclass within the package has increased the method's accessibility.
Until recently, implementations have interpreted this definition loosely.
As a result: