Java private修饰符失效的原因
失效之Java内部类
在一个内部类里访问外部类的private成员变量或者方法。
publicclassOuterClass{
privateStringlanguage="en";
privateStringregion="US";
publicclassInnerClass{
publicvoidprintOuterClassPrivateFields(){
Stringfields="language="+language+";region="+region;
System.out.println(fields);
}
}
publicstaticvoidmain(String[]args){
OuterClassouter=newOuterClass();
OuterClass.InnerClassinner=outer.newInnerClass();
inner.printOuterClassPrivateFields();
}
}
查看原因
使用javap命令查看一下生成的class文件
15:30javap-cOuterClass
Compiledfrom"OuterClass.java"
publicclassOuterClassextendsjava.lang.Object{
publicOuterClass();
Code:
0:aload_0
1:invokespecial#11;//Methodjava/lang/Object."":()V
4:aload_0
5:ldc#13;//Stringen
7:putfield#15;//Fieldlanguage:Ljava/lang/String;
10:aload_0
11:ldc#17;//StringUS
13:putfield#19;//Fieldregion:Ljava/lang/String;
16:return
publicstaticvoidmain(java.lang.String[]);
Code:
0:new#1;//classOuterClass
3:dup
4:invokespecial#27;//Method"":()V
7:astore_1
8:new#28;//classOuterClassInnerClass
11:dup
12:aload_1
13:dup
14:invokevirtual#30;//Methodjava/lang/Object.getClass:()Ljava/lang/Class;
17:pop
18:invokespecial#34;//MethodOuterClassInnerClass."":(LOuterClass;)V
21:astore_2
22:aload_2
23:invokevirtual#37;//MethodOuterClassInnerClass.printOuterClassPrivateFields:()V
26:return
staticjava.lang.Stringaccess0(OuterClass);
Code:
0:aload_0
1:getfield#15;//Fieldlanguage:Ljava/lang/String;
4:areturn
staticjava.lang.Stringaccess1(OuterClass);
Code:
0:aload_0
1:getfield#19;//Fieldregion:Ljava/lang/String;
4:areturn
}
在这里有一个OuterClass方法,
staticjava.lang.Stringaccess0(OuterClass); Code: 0:aload_0 1:getfield#15;//Fieldlanguage:Ljava/lang/String; 4:areturn staticjava.lang.Stringaccess1(OuterClass); Code: 0:aload_0 1:getfield#19;//Fieldregion:Ljava/lang/String; 4:areturn }
根据注释,可以知道access0返回outerClass的language属性,access1返回outerClass的region属性,并且这两个方法都接受OuterClass的实例作为参数,
对这两个方法进行反编译。
15:37javap-cOuterClassInnerClass
Compiledfrom"OuterClass.java"
publicclassOuterClassInnerClassextendsjava.lang.Object{
finalOuterClassthis0;
publicOuterClassInnerClass(OuterClass);
Code:
0:aload_0
1:aload_1
2:putfield#10;//Fieldthis0:LOuterClass;
5:aload_0
6:invokespecial#12;//Methodjava/lang/Object."":()V
9:return
publicvoidprintOuterClassPrivateFields();
Code:
0:new#20;//classjava/lang/StringBuilder
3:dup
4:ldc#22;//Stringlanguage=
6:invokespecial#24;//Methodjava/lang/StringBuilder."":(Ljava/lang/String;)V
9:aload_0
10:getfield#10;//Fieldthis0:LOuterClass;
13:invokestatic#27;//MethodOuterClass.access0:(LOuterClass;)Ljava/lang/String;
16:invokevirtual#33;//Methodjava/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19:ldc#37;//String;region=
21:invokevirtual#33;//Methodjava/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24:aload_0
25:getfield#10;//Fieldthis0:LOuterClass;
28:invokestatic#39;//MethodOuterClass.access1:(LOuterClass;)Ljava/lang/String;
31:invokevirtual#33;//Methodjava/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34:invokevirtual#42;//Methodjava/lang/StringBuilder.toString:()Ljava/lang/String;
37:astore_1
38:getstatic#46;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
41:aload_1
42:invokevirtual#52;//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
45:return
}
下面代码调用access$0的代码,其目的是得到OuterClass的language私有属性。
13:invokestatic#27;//MethodOuterClass.access$0:(LOuterClass;)Ljava/lang/String;
下面代码调用了access$1的代码,其目的是得到OutherClass的region私有属性。
28:invokestatic#39;//MethodOuterClass.access$1:(LOuterClass;)Ljava/lang/String;
即,在内部类构造的时候,会有外部类的引用传递进来,并且作为内部类的一个属性,所以内部类会持有一个其外部类的应用。
this$0就是内部类持有的外部类引用,通过构造方法传递引用并赋值。
finalOuterClassthis0; publicOuterClassInnerClass(OuterClass); Code: 0:aload_0 1:aload_1 2:putfield#10;//Fieldthis$0:LOuterClass; 5:aload_0 6:invokespecial#12;//Methodjava/lang/Object."":()V 9:return
继续失效
publicclassAnotherOuterClass{
publicstaticvoidmain(String[]args){
InnerClassinner=newAnotherOuterClass().newInnerClass();
System.out.println("InnerClassFiled="+inner.x);
}
classInnerClass{
privateintx=10;
}
}
和上面一样,使用Javap反编译一下
16:03javap-cAnotherOuterClassInnerClass
Compiledfrom"AnotherOuterClass.java"
classAnotherOuterClassInnerClassextendsjava.lang.Object{
finalAnotherOuterClassthis0;
AnotherOuterClassInnerClass(AnotherOuterClass);
Code:
0:aload_0
1:aload_1
2:putfield#12;//Fieldthis0:LAnotherOuterClass;
5:aload_0
6:invokespecial#14;//Methodjava/lang/Object."":()V
9:aload_0
10:bipush10
12:putfield#17;//Fieldx:I
15:return
staticintaccess0(AnotherOuterClassInnerClass);
Code:
0:aload_0
1:getfield#17;//Fieldx:I
4:ireturn
}
编译器自动生成了一个access$0一次来获取x的值
AnotherOuterClass.class的反编译结果
16:08javap-cAnotherOuterClass
Compiledfrom"AnotherOuterClass.java"
publicclassAnotherOuterClassextendsjava.lang.Object{
publicAnotherOuterClass();
Code:
0:aload_0
1:invokespecial#8;//Methodjava/lang/Object."":()V
4:return
publicstaticvoidmain(java.lang.String[]);
Code:
0:new#16;//classAnotherOuterClassInnerClass
3:dup
4:new#1;//classAnotherOuterClass
7:dup
8:invokespecial#18;//Method"":()V
11:dup
12:invokevirtual#19;//Methodjava/lang/Object.getClass:()Ljava/lang/Class;
15:pop
16:invokespecial#23;//MethodAnotherOuterClassInnerClass."":(LAnotherOuterClass;)V
19:astore_1
20:getstatic#26;//Fieldjava/lang/System.out:Ljava/io/PrintStream;
23:new#32;//classjava/lang/StringBuilder
26:dup
27:ldc#34;//StringInnerClassFiled=
29:invokespecial#36;//Methodjava/lang/StringBuilder."":(Ljava/lang/String;)V
32:aload_1
33:invokestatic#39;//MethodAnotherOuterClassInnerClass.access0:(LAnotherOuterClassInnerClass;)I
36:invokevirtual#43;//Methodjava/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39:invokevirtual#47;//Methodjava/lang/StringBuilder.toString:()Ljava/lang/String;
42:invokevirtual#51;//Methodjava/io/PrintStream.println:(Ljava/lang/String;)V
45:return
}
其中这句话,直接说明通过内部类的实例,获取到私有属性x的操作。
invokestatic#39;//MethodAnotherOuterClassInnerClass.access0:(LAnotherOuterClass$InnerClass;)I
在官网文档中是这样说道的,如果(内部类的)成员和构造方法设定成了私有修饰符,当且仅当其外部类访问时是允许的。
如何保证不被访问
使用的方法相当简单,使用匿名内部类的方法实现
publicclassPrivateToOuter{
RunnablemRunnable=newRunnable(){
privateintx=10;
@Override
publicvoidrun(){
System.out.println(x);
}
};
publicstaticvoidmain(String[]args){
PrivateToOuterp=newPrivateToOuter();
//System.out.println("anonymousclassprivatefiled="+p.mRunnable.x);//notallowed
p.mRunnable.run();//allowed
}
}
以上就是Javaprivate修饰符失效的原因的详细内容,更多关于Javaprivate修饰符失效的资料请关注毛票票其它相关文章!