Flask接口签名sign原理与实例代码浅析
283
2022-11-16
Java private修饰符失效的原因
失效之java内部类
在一个内部类里访问外部类的private成员变量或者方法。
public class OuterClass {
private String language = "en";
private String region = "US";
public class InnerClass {
public void printOuterClassPrivateFields() {
String fields = "language=" + language + ";region=" + region;
System.out.println(fields);
}
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.printOuterClassPrivateFields();
}
}
查看原因
使用javap命令查看一下生成的class文件
15:30 javap -c OuterClass
Compiled from "OuterClass.java"
public class OuterClass extends java.lang.Object{
public OuterClass();
Code:
0: aload_0
1: invokespecial #11; //Method java/lang/Object."
4: aload_0
5: ldc #13; //String en
7: putfield #15; //Field language:Ljava/lang/String;
10: aload_0
11: ldc #17; //String US
13: putfield #19; //Field region:Ljava/lang/String;
16: return
public static void main(java.lang.String[]);
Code:
0: new #1; //class OuterClass
3: dup
4: invokespecial #27; //Method "
7: astore_1
8: new #28; //class OuterClassInnerClass
11: dup
12: aload_1
13: dup
14: invokevirtual #30; //Method java/lang/Object.getClass:()Ljava/lang/Class;
17: pop
18: invokespecial #34; //Method OuterClassInnerClass."
21: astore_2
22: aload_2
23: invokevirtual #37; //Method OuterClassInnerClass.printOuterClassPrivateFields:()V
26: return
static java.lang.String access0(OuterClass);
Code:
0: aload_0
1: getfield #15; //Field language:Ljava/lang/String;
4: areturn
static java.lang.String access1(OuterClass);
Code:
0: aload_0
1: getfield #19; //Field region:Ljava/lang/String;
4: areturn
}
在这里有一个OuterClass方法,
static java.lang.String access0(OuterClass);
Code:
0: aload_0
1: getfield #15; //Field language:Ljava/lang/String;
4: areturn
static java.lang.String access1(OuterClass);
Code:
0: aload_0
1: getfield #19; //Field region:Ljava/lang/String;
4: areturn
}
根据注释,可以知道access0返回outerClass的language属性,access1返回outerClass的region属性,并且这两个方法都zVkHtMkKb接受OuterClass的实例作为参数,
对这两个方法进行反编译。
15:37 javap -c OuterClassInnerClass
Compiled from "OuterClass.java"
public class OuterClassInnerClass extends java.lang.Object{
final OuterClass this0;
public OuterClassInnerClass(OuterClass);
Code:
0: aload_0
1: aload_1
2: putfield #10; //Field this0:LOuterClass;
5: aload_0
6: invokespecial #12; //Method java/lang/Object."
9: return
public void printOuterClassPrivateFields();
Code:
0: new #20; //class java/lang/StringBuilder
3: dup
4: ldc #22; //String language=
6: invokespecial #24; //Method java/lang/StringBuilder."
9: aload_0
10: getfield #10;zVkHtMkKb //Field this0:LOuterClass;
13: invokestatic #27; //Method OuterClass.access0:(LOuterClass;)Ljava/lang/String;
16: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #37; //String ;region=
21: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_0
25: getfield #10; //Field this0:LOuterClass;
28: invokestatic #39; //Method OuterClass.access1:(LOuterClass;)Ljava/lang/String;
31: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
34: invokevirtual #42; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
37: astore_1
38: getstatic #46; //Field java/lang/System.out:Ljava/io/PrintStream;
41: aload_1
42: invokevirtual #52; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
}
下面代码调用azVkHtMkKbccess$0的代码,其目的是得到OuterClass的language 私有属性。
13: invokestatic #27; //Method OuterClass.access$0:(LOuterClass;)Ljava/lang/String;
下面代码调用了access$1的代码,其目的是得到OutherClass的region 私有属性。
28: invokestatic #39; //Method OuterClass.access$1:(LOuterClass;)Ljava/lang/String;
即,在内部类构造的时候,会有外部类的引用传递进来,并且作为内部类的一个属性,所以内部类会持有一个其外部类的应用。
this$0就是内部类持有的外部类引用,通过构造方法传递引用并赋值。
final OuterClass this0;
public OuterClassInnerClass(OuterClass);
Code:
0: aload_0
1: aload_1
2: putfield #10; //Field this$0:LOuterClass;
5: aload_0
6: invokespecial #12; //Method java/lang/Object."
9: return
继续失效
public class AnotherOuterClass {
public static void main(String[] args) {
InnerClass inner = new AnotherOuterClass().new InnerClass();
System.out.println("InnerClass Filed = " + inner.x);
}
class InnerClass {
private int x = 10;
}
}
和上面一样,使用Javap反编译一下
16:03 javap -c AnotherOuterClassInnerClass
Compiled from "AnotherOuterClass.java"
class AnotherOuterClassInnerClass extends java.lang.Object{
zVkHtMkKbfinal AnotherOuterClass this0;
AnotherOuterClassInnerClass(AnotherOuterClass);
Code:
0: aload_0
1: aload_1
2: putfield #12; //Field this0:LAnotherOuterClass;
5: aload_0
6: invokespecial #14; //Method java/lang/Object."
9: aload_0
10: bipush 10
12: putfield #17; //Field x:I
15: return
static int access0(AnotherOuterClassInnerClass);
Code:
0: aload_0
1: getfield #17; //Field x:I
4: ireturn
}
编译器自动生成了一个access$0一次来获取x的值
AnotherOuterClass.class的反编译结果
16:08 javap -c AnotherOuterClass
Compiled from "AnotherOuterClass.java"
public class AnotherOuterClass extends java.lang.Object{
public AnotherOuterClass();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."
4: return
public static void main(java.lang.String[]);
Code:
0: new #16; //class AnotherOuterClassInnerClass
3: dup
4: new #1; //class AnotherOuterClass
7: dup
8: invokespecial #18; //Method "
11: dup
12: invokevirtual #19; //Method java/lang/Object.getClass:()Ljava/lang/Class;
15: pop
16: invokespecial #23; //Method AnotherOuterClassInnerClass."
19: astore_1
20: getstatic #26; //Field java/lang/System.out:Ljava/io/PrintStream;
23: new #32; //class java/lang/StringBuilder
26: dup
27: ldc #34; //String InnerClass Filed =
29: invokespecial #36; //Method java/lang/StringBuilder."
32: aload_1
33: invokestatic #39; //Method AnotherOuterClassInnerClass.access0:(LAnotherOuterClassInnerClass;)I
36: invokevirtual #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39: invokevirtual #47; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: invokevirtual #51; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
}
其中这句话,直接说明通过内部类的实例,获取到私有属性x的操作。
invokestatic #39; //Method AnotherOuterClassInnerClass.access0:(LAnotherOuterClass$InnerClass;)I
在官网文档中是这样说道的,如果(内部类的)成员和构造方法设定成了私有修饰符,当且仅当其外部类访问时是允许的。
如何保证不被访问
使用的方法相当简单,使用匿名内部类的方法实现
public class PrivateToOuter {
Runnable mRunnable = new Runnable(){
private int x=10;
@Override
public void run() {
System.out.println(x);
}
};
public static void main(String[] args){
PrivateToOuter p = new PrivateToOuter();
//System.out.println("anonymous class private filed= "+ p.mRunnable.x); //not allowed
p.mRunnable.run(); // allowed
}
}
以上就是Java private修饰符失效的原因的详细内容,更多关于Java private修饰符失效的资料请关注我们其它相关文章!
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~