class TestMemberOuter1{
private int data=30;
class Inner{
void msg(){System.out.println("data is "+data);}
}
void display(){
Inner in=new Inner();
in.msg();
}
public static void main(String args[]){
TestMemberOuter1 obj=new TestMemberOuter1();
obj.display();
}
}
为什么innerclass能够访问外部类的私有成员?
我想知道什么实现[在较低级别(可能在内存级别或特定于java实现或任何其他不确定)]能够在java中实现这种行为。
答案 0 :(得分:3)
我认为你不需要任何内存级修改或逻辑实现来实现这一点,我认为java在内存级别会有任何巨大的代码逻辑来实现它。
记忆与它无关。 Private,public和protected只是一个访问过滤器,无论是私有,公共还是受保护,所有这些变量都将驻留在为对象分配的同一内存中。
私有,公共或受保护变量没有不同的内存分配。它们最终都是同一物体的属性。
然后编译器如何处理这个???
比这简单。
这些访问过滤器清楚地告知应允许他们访问的上下文。
私有:只有白色的类:)每当编译器看到提示被访问的变量时,任何在类的外边都会标记错误,这就是全部。
受保护:同一个包中的所有类:)每当编译器看到被保护的变量被访问时,任何out包都将标记错误,这就是全部。
公共:访问所有:)没有标志。
记得在上下文中访问变量导致编译器错误而不是运行时错误?出于同样的原因。
你不需要背后的巨大逻辑,只需保留私有,受保护和公共变量的列表,并检查它们的用法是否合适。
修改强> 根据您更新的问题"为什么内部类能够访问外部类的私有成员?"
从我上面解释的相同类比得出结论,允许在类中的任何地方访问私有变量。
现在你的内部类被宣布在哪里?作为你外在阶级的一部分本身并不是它。所以当你在内部类中访问外部类的私有变量时,编译器对它没有任何问题,因为你的内部类本身位于外部类中。
我希望我的回答有点意义:)快乐的编码。
答案 1 :(得分:0)
目前,内部类被编译为不同的类文件,但是当跨嵌套类访问private
成员时,编译器将插入合成帮助器方法。合成方法本身将具有包私有访问权限,并在其自己的类中执行对private
成员的访问。
这可以用private
方法证明,因为它们的执行可以被跟踪,并将显示这些辅助方法的执行:
public class OuterClass {
static class InnerClass {
private static void test() {
OuterClass.privateMethod();
}
}
private static void privateMethod() {
Thread.dumpStack();
}
public static void main(String[] args) {
InnerClass.test();
}
}
运行此程序将打印:
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1329)
at OuterClass.privateMethod(OuterClass.java:9)
at OuterClass.access$000(OuterClass.java:2)
at OuterClass$InnerClass.test(OuterClass.java:5)
at OuterClass$InnerClass.access$100(OuterClass.java:3)
at OuterClass.main(OuterClass.java:12)
这些嵌套类被编译为两个不同的类文件OuterClass.class
和OuterClass$InnerClass.class
。您可以看到编译器已将合成方法access$100
插入到OuterClass$InnerClass
中,这允许main
OuterClass
方法调用private
方法{{1}内部类。这个内部类方法又在外部类中调用了一个合成方法test
,允许在access$000
中调用privateMethod()
。
请注意,这种访问与使用Java 8的lambda表达式和方法引用执行的OuterClass
成员访问不同。对于在该上下文中执行的成员访问,编译器不会生成任何辅助方法,并且有意未指定JVM使访问成为可能的方式,但我们可以说对于Oracle当前的JRE实现,将有一个运行时生成的类,确实能够绕过 private
成员的访问限制,例如
private
从import java.util.function.Consumer;
public class OuterClass {
static class InnerClass {
static final Consumer<Runnable> TEST_METHOD=InnerClass::test;
private static void test(Runnable outerMethod) {
outerMethod.run();
}
}
private static void privateMethod() {
Thread.dumpStack();
}
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
InnerClass.TEST_METHOD.accept(OuterClass::privateMethod);
}
}
开始,它会打印:
1.8.0_65
不显示此类辅助方法,但也过滤掉运行时生成的类。将java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Thread.java:1329)
at OuterClass.privateMethod(OuterClass.java:12)
at OuterClass$InnerClass.test(OuterClass.java:8)
at OuterClass.main(OuterClass.java:16)
更改为
privateMethod()
揭示
private static void privateMethod() {
for(StackTraceElement e:Thread.getAllStackTraces().get(Thread.currentThread()))
System.out.println("\tat "+e);
}
生成的类具有访问 at java.lang.Thread.dumpThreads(Native Method)
at java.lang.Thread.getAllStackTraces(Thread.java:1603)
at OuterClass.privateMethod(OuterClass.java:12)
at OuterClass$$Lambda$2/135721597.run(Unknown Source)
at OuterClass$InnerClass.test(OuterClass.java:8)
at OuterClass$InnerClass$$Lambda$1/471910020.accept(Unknown Source)
at OuterClass.main(OuterClass.java:16)
成员的OuterClass$InnerClass$$Lambda$1/471910020
和OuterClass$$Lambda$2/135721597
等奇特名称。请注意,这些类的生成是由有权访问这些private
成员的类触发的,这些成员在允许创建此类函数对象之前已经过检查。