Invoking a private
method is only possible through an expression of exactly the declaring type, regardless of the scenario.
Let’s explain it with the simplest example
public class A {
public static void main(String[] args) {
B b = new B();
b.someMethod(); // does not compile
A a = b;
a.someMethod(); // no problem
}
private void someMethod() {}
}
class B extends A {
}
You might expect this to compile using b.someMethod()
to invoke A
’s someMethod()
. But what if B
was declared as
class B extends A {
public void someMethod() {}
}
This is possible, as the private void someMethod()
is not inherited, so public void someMethod()
does not override it. But it should be clear that now b.someMethod()
should invoke B
’s method.
So if it was allowed that b.someMethod()
ends up at a private
method of A
, it would depend on whether B
declares another someMethod()
, at which actual method the call will end up. And that obviously contradicts the entire concept of private
methods. private
methods are not inherited and never overridden, so it should not depend on the subclass, whether a call ends up at a private
method or a subclass’ method.
Your example is similar. The anonymous inner class that implements I
could declare its own test()
method, e.g. Runnable test2 = ((new I() {void test() {}}))::test;
so it would depend on that anonymous inner class, whether the private
method of I
or a method of that anonymous inner class gets invoked, which would be unacceptable. Of course, with such an inner class, directly preceding the invocation or method reference, a reader can immediately tell, at which method the invocation will end up, but it would be very inconsistent, if this was allowed for an anonymous inner class but nothing else.
The private
method of I
is accessible to A
as it is a the nested interface, but as shown with the simpler example above, the rule is not about accessibility, as the rule even applies when the private
method is within the same class as the caller.