Java private修饰符失效的原因

网友投稿 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."":()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 "":()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."":(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属性,并且这两个方法都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."":()V

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."":(Ljava/lang/String;)V

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."":()V

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."":()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的反编译结果

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."":()V

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 "":()V

11: dup

12: invokevirtual #19; //Method java/lang/Object.getClass:()Ljava/lang/Class;

15: pop

16: invokespecial #23; //Method AnotherOuterClassInnerClass."":(LAnotherOuterClass;)V

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."":(Ljava/lang/String;)V

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小时内删除侵权内容。

上一篇:详解Java Web如何限制访问的IP的两种方法
下一篇:Spring注解配置AOP导致通知执行顺序紊乱解决方案
相关文章

 发表评论

暂时没有评论,来抢沙发吧~