时间:2021-05-20
失效之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 OuterClassCompiled from "OuterClass.java"public class OuterClass extends java.lang.Object{public OuterClass(); Code: 0: aload_0 1: invokespecial #11; //Method java/lang/Object."<init>":()V 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 "<init>":()V 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."<init>":(LOuterClass;)V 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属性,并且这两个方法都接受OuterClass的实例作为参数,
对这两个方法进行反编译。
下面代码调用access$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就是内部类持有的外部类引用,通过构造方法传递引用并赋值。
继续失效
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 AnotherOuterClassInnerClassCompiled from "AnotherOuterClass.java"class AnotherOuterClassInnerClass extends java.lang.Object{final 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."<init>":()V 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的反编译结果
其中这句话,直接说明通过内部类的实例,获取到私有属性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修饰符失效的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
Java有四种访问权限,其中三种有访问权限修饰符,分别为private,public和protected,还有一种不带任何修饰符:1.private:Java语
1.private修饰符private修饰符用于设置类或类成员的访问权限仅为所属类的内部,private也被称为私有修饰符。某些时候需要访问私有类成员时,可通过
大数据Scala系列之类1.类的定义Scala访问修饰符基本和Java的一样,分别有:private,protected,public。如果没有指定访问修饰符符
Java中四种访问权限总结一、Java中有四种访问权限,其中三种有访问权限修饰符,分别为private、public、protected,还有一种不带任何修饰符
一.在java中提供的一些修饰符,这些修饰符可以修饰类、变量和方法,在java中常见的修饰符有:abstract(抽象的)、static(静态的)、public