我不明白为什么这会编译.f()和g()在内部类中是可见的,尽管是私有的.他们是特殊的,因为他们是内部阶级?
如果A和B不是静态类,它仍然是相同的.
class NotPrivate { private static class A { private void f() { new B().g(); } } private static class B { private void g() { new A().f(); } } }
TofuBeer.. 30
(编辑:扩展答案以回答一些评论)
编译器获取内部类并将它们转换为顶级类.由于私有方法仅对内部类可用,因此编译器必须添加具有包级访问权限的新"合成"方法,以便顶级类可以访问它.
这样的东西($ 1由编译器添加):
class A { private void f() { final B b; b = new B(); // call changed by the compiler b.$g(); } // method generated by the compiler - visible by classes in the same package void $f() { f(); } } class B { private void g() { final A a; a = new A(); // call changed by the compiler a.$f(); } // method generated by the compiler - visible by classes in the same package void $g() { g(); } }
非静态类是相同的,但它们添加了对外部类的引用,以便可以在其上调用方法.
Java这样做的原因是他们不想要求VM更改来支持内部类,因此所有更改都必须在编译器级别.
编译器获取内部类并将其转换为顶级类(因此,在VM级别,不存在内部类).然后编译器还必须生成新的"转发"方法.它们是在包级别(非公共)创建的,以确保只有同一个包中的类才能访问它们.编译器还将对私有方法的方法调用更新为生成的"转发"方法.
您可以避免编译器生成方法我将方法声明为"package"(缺少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); } } } }
Eric Petroel.. 14
我认为这句话总结得很好:
...内部类可以访问声明类的所有成员,甚至是私有成员.事实上,内部阶级本身据说是班上的一员; 因此,遵循面向对象工程的规则,它应该可以访问该类的所有成员.
接下来,由于两个内部类实际上只是包含类的一部分,因此它们也应该能够访问彼此的私有成员.
(编辑:扩展答案以回答一些评论)
编译器获取内部类并将它们转换为顶级类.由于私有方法仅对内部类可用,因此编译器必须添加具有包级访问权限的新"合成"方法,以便顶级类可以访问它.
这样的东西($ 1由编译器添加):
class A { private void f() { final B b; b = new B(); // call changed by the compiler b.$g(); } // method generated by the compiler - visible by classes in the same package void $f() { f(); } } class B { private void g() { final A a; a = new A(); // call changed by the compiler a.$f(); } // method generated by the compiler - visible by classes in the same package void $g() { g(); } }
非静态类是相同的,但它们添加了对外部类的引用,以便可以在其上调用方法.
Java这样做的原因是他们不想要求VM更改来支持内部类,因此所有更改都必须在编译器级别.
编译器获取内部类并将其转换为顶级类(因此,在VM级别,不存在内部类).然后编译器还必须生成新的"转发"方法.它们是在包级别(非公共)创建的,以确保只有同一个包中的类才能访问它们.编译器还将对私有方法的方法调用更新为生成的"转发"方法.
您可以避免编译器生成方法我将方法声明为"package"(缺少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); } } } }
我认为这句话总结得很好:
...内部类可以访问声明类的所有成员,甚至是私有成员.事实上,内部阶级本身据说是班上的一员; 因此,遵循面向对象工程的规则,它应该可以访问该类的所有成员.
接下来,由于两个内部类实际上只是包含类的一部分,因此它们也应该能够访问彼此的私有成员.