美文网首页
细说 | "失效"的private修饰符

细说 | "失效"的private修饰符

作者: 是阿胖胖吖 | 来源:发表于2020-10-08 15:42 被阅读0次

本篇将会说到失效的private修饰符

前言

在Java编程里,使用private关键字修饰了一个成员,只有成员内部可以访问,其余成员都不可访问,今天说明一下private功能失效的问题。

整理了一份Java核心知识点。覆盖了JVM、锁、并发、Java反射、Spring原理、微服务、Zookeeper、数据库、数据结构等大量知识点。基本上涵盖了Java架构所有的技术知识点的资料,还覆盖了大厂面试题,同时也有一些springboot等项目源码分享给大家

由于资料图片太多就不一一的展示出来了

如果需要获取到这个文档的话帮忙转发一下然后再关注我私信回复“架构资料”得到获取方式吧!

失效之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 OuterClass$InnerClass

   11: dup

   12: aload_1

   13: dup

   14: invokevirtual    #30; //Method java/lang/Object.getClass:()Ljava/lang/Class;

   17: pop

   18: invokespecial    #34; //Method OuterClass$InnerClass."<init>":(LOuterClass;)V

   21: astore_2

   22: aload_2

   23: invokevirtual    #37; //Method OuterClass$InnerClass.printOuterClassPrivateFields:()V

   26: return

static java.lang.String access$0(OuterClass);

  Code:

   0:  aload_0

   1:  getfield #15; //Field language:Ljava/lang/String;

   4:  areturn

static java.lang.String access$1(OuterClass);

  Code:

   0:  aload_0

   1:  getfield #19; //Field region:Ljava/lang/String;

   4:  areturn

}

在这里有一个OuterClass方法,

static java.lang.String access$0(OuterClass);

  Code:

   0:  aload_0

   1:  getfield #15; //Field language:Ljava/lang/String;

   4:  areturn

static java.lang.String access$1(OuterClass);

  Code:

   0:  aload_0

   1:  getfield #19; //Field region:Ljava/lang/String;

   4:  areturn

}

根据注释,可以知道access1返回outerClass的region属性,并且这两个方法都接受OuterClass的实例作为参数, 对这两个方法进行反编译。

15:37 $ javap -c OuterClass$InnerClass

Compiled from "OuterClass.java"

public class OuterClass$InnerClass extends java.lang.Object{

final OuterClass this$0;

public OuterClass$InnerClass(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 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 this$0:LOuterClass;

   13: invokestatic #27; //Method OuterClass.access$0:(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 this$0:LOuterClass;

   28: invokestatic #39; //Method OuterClass.access$1:(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 this$0;

public OuterClass$InnerClass(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 AnotherOuterClass$InnerClass

Compiled from "AnotherOuterClass.java"

class AnotherOuterClass$InnerClass extends java.lang.Object{

final AnotherOuterClass this$0;

AnotherOuterClass$InnerClass(AnotherOuterClass);

  Code:

   0:  aload_0

   1:  aload_1

   2:  putfield #12; //Field this$0: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 access$0(AnotherOuterClass$InnerClass);

  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 AnotherOuterClass$InnerClass

   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 AnotherOuterClass$InnerClass."<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 AnotherOuterClass$InnerClass.access$0:(LAnotherOuterClass$InnerClass;)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的操作。

33:   invokestatic #39; //Method AnotherOuterClass$InnerClass.access$0:(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

  }

}

相关文章

  • 细说 | "失效"的private修饰符

    本篇将会说到失效的private修饰符 前言 在Java编程里,使用private关键字修饰了一个成员,只有成员内...

  • spark题05

    1.scala中private 与 private[this] 修饰符的区别? private[包名],priva...

  • 可见修饰符

    修饰符: public、private、protected、internal默认为public。private的可...

  • Java 权限修饰符

    修饰符:权限修饰符:private,默认的,protected,public状态修饰符:static,final抽...

  • 权限修饰符+封装+final+static

    修饰符 权限修饰符: public protected 默认 private 状态修饰符: static fina...

  • C#基础面试题

    1.简述private、protected、pubic、internal修饰符的访问权限 答: private :...

  • C#面试题

    1.简述 private、 protected、 public、internal 修饰符的访问权限答private...

  • 关于类的总结

    访问修饰符public,private,protected,以及不写(默认)时的区别? | 修饰符 ...

  • 访问控制符有几个,分别是什么

    4个 public /protected/默认/private 访问控制修饰符 public和private pr...

  • Java基础-修饰符

    常见的修饰符 1.分类: 权限修饰符: private , 默认 , protected , public状态修饰...

网友评论

      本文标题:细说 | "失效"的private修饰符

      本文链接:https://www.haomeiwen.com/subject/reqhpktx.html