Java private修饰符失效的原因

 更新时间:2020年10月23日 10:54:58   作者:melovemingming  
在Java编程里,使用private关键字修饰了一个成员,只有成员内部可以访问,其余成员都不可访问,今天说明一下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."<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的实例作为参数,
对这两个方法进行反编译。

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."<init>":()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."<init>":(Ljava/lang/String;)V
 9: aload_0
 10: getfield #10; //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
}

下面代码调用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就是内部类持有的外部类引用,通过构造方法传递引用并赋值。

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

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."<init>":()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 "<init>":()V
 11: dup
 12: invokevirtual #19; //Method java/lang/Object.getClass:()Ljava/lang/Class;
 15: pop
 16: invokespecial #23; //Method AnotherOuterClassInnerClass."<init>":(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."<init>":(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修饰符失效的资料请关注脚本之家其它相关文章!

相关文章

  • 实例讲解Java基础之反射

    实例讲解Java基础之反射

    今天小编就为大家分享一篇关于实例讲解Java基础之反射,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-03-03
  • Java IO流之字符缓冲流实例详解

    Java IO流之字符缓冲流实例详解

    这篇文章主要介绍了Java IO流之字符缓冲流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-05-05
  • Java抽象定义以及举例代码

    Java抽象定义以及举例代码

    这篇文章主要给大家介绍了关于Java抽象定义以及举例的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Mybatis Plus 字段为空值时执行更新方法未更新解决方案

    Mybatis Plus 字段为空值时执行更新方法未更新解决方案

    这篇文章主要介绍了Mybatis Plus 字段为空值时执行更新方法未更新解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • java中HashMap.values()转为ArrayList()问题

    java中HashMap.values()转为ArrayList()问题

    这篇文章主要介绍了java中HashMap.values()转为ArrayList()问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • 关于Java大整数运算之BigInteger类

    关于Java大整数运算之BigInteger类

    这篇文章主要介绍了关于Java大整数运算之BigInteger类,BigInteger提供高精度整型数据类型及相关操作,所有操作中,都以二进制补码形式表示,需要的朋友可以参考下
    2023-05-05
  • Maven如何修改打包文件名称

    Maven如何修改打包文件名称

    这篇文章主要介绍了Maven如何修改打包文件名称问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • springboot的yml配置文件通过db2的方式整合mysql的教程

    springboot的yml配置文件通过db2的方式整合mysql的教程

    这篇文章主要介绍了springboot的yml配置文件通过db2的方式整合mysql的教程,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Spring Cloud Feign的文件上传实现的示例代码

    Spring Cloud Feign的文件上传实现的示例代码

    这篇文章主要介绍了Spring Cloud Feign的文件上传实现的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-03-03
  • java中的session对象及其常用方法小结

    java中的session对象及其常用方法小结

    这篇文章主要介绍了java中的session对象及其常用方法小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07

最新评论