(编辑:扩展了答案以回答一些评论)
编译器会将内部类转换为顶级类。由于私有方法仅对内部类可用,因此编译器必须添加新的“合成”方法,其具有包级别访问权限,以便顶级类可以访问它。
大致如此($ 是编译器添加的):
class A
{
private void f()
{
final B b;
b = new B();
b.$g();
}
void $f()
{
f();
}
}
class B
{
private void g()
{
final A a;
a = new A();
a.$f();
}
void $g()
{
g();
}
}
非静态类与普通类相同,但是它们还会包含对外部类的引用,以便可以在其中调用方法。
Java 采取这种方式的原因是他们不想要求 VM 支持内部类的更改,所以所有更改都必须在编译器级别完成。
编译器接收内部类并将其转换为顶层类(因此,在 VM 级别上不存在内部类)。编译器还必须生成新的“转发”方法。它们被制作在包级别(而不是公共级别),以确保只有在同一包中的类才能访问它们。编译器还更新了对私有方法的方法调用,使其指向生成的“转发”方法。
如果将方法声明为“包级别”(即没有 public、private 和 protected),则可以避免编译器生成该方法。但缺点是包中的任何类都可以调用这些方法。
编辑:
是的,你可以调用生成的(合成的)方法,但请不要这样做!
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class Main
{
public static void main(final String[] argv)
throws Exception
{
final Class<?> clazz;
clazz = Class.forName("NotPrivate$A");
for(final Method method : clazz.getDeclaredMethods())
{
if(method.isSynthetic())
{
final Constructor constructor;
final Object instance;
constructor = clazz.getDeclaredConstructor(new Class[0]);
constructor.setAccessible(true);
instance = constructor.newInstance();
method.setAccessible(true);
method.invoke(null, instance);
}
}
}
}