zoukankan      html  css  js  c++  java
  • JVM-内部类分析

    一、内部类和外部类调用及字节码解释

    • 外部类使用 内部类:
      • 非静态内部类:
        • JVM字节码 非静态内部类类 多了一个外部类对象的属性:final synthetic Field this$0:"Ljavap/loader/OuterClass;"; // 非静态内部类,合成的属性:外部类对象
        • JVM生成的构造方法要传入外部类对象,并初始化上述属性:public Method "<init>":"(Ljavap/loader/OuterClass;)V" // 非静态内部类的构造方法,JVM默认把外部类作为参数传递进来
          • 初始化该属性:putfield Field this$0:"Ljavap/loader/OuterClass;"; // 把内部类的一个属性初始化为外部类的实例
          • 初始化Object:invokespecial Method java/lang/Object."<init>":"()V";
        • 基于上述两点,外部类使用内部类时:new OuterClass().new InnerClass()  -- 必须先new外部类
      • 静态内部类:
        • 无外部类对象的属性
        • 构造方法不需要传入外部类对象(即无需先存在外部类对象,才能存在内部类对象
        • 基于上述两点,外部类使用内部类时:new OuterClass.InnerStaticClass() -- 无需先new外部类
      •  
    • 内部类使用 外部类:
      • 内部类访问外部类的静态属性如String类型,JVM会为外部类合成一个方法:static synthetic Method access$000:"()Ljava/lang/String;" ,可以直接访问OuterClass.static_msg
      • 内部类调用外部类的静态方法void staticShow(),JVM会为外部类合成一个方法:static synthetic Method access$100:"()V",可以直接访问OuterClass.staticShow()
      • 内部类调用外部类的实例方法void show(),JVM会为外部类合成一个方法并定义为static,static synthetic Method access$200:"(Ljavap/loader/OuterClass;)V",因此需要传递参数(外部类对象)
        • 调用方式:非静态内部类问外部类非静态方法(属性),这样子再new一个外部类没必要,可以直接OuterClass.this.show() 或 OuterClass.this.msg,因为非静态内部类初始化的时候已经传入外部类对象
        • 调用方式:静态内部类问外部类非静态方法(属性),直接OuterClass.this.show() 或 OuterClass.this.msg 会报编译错误 'javap.loader.OuterClass.this' cannot be referenced from a static context,因为静态内部类初始化的时候未传入外部类对象 

    例子1:

     1 package javap.loader;
     2 
     3 /* 下面程序演示如何在java中创建静态内部类和非静态内部类 */
     4 class OuterClass{
     5 
     6     private static String static_msg = "GeeksForGeeks_static_msg";
     7 
     8     private String msg = "GeeksForGeeks_msg";
     9 
    10 
    11     // 静态内部类
    12     public static class InnerStaticClass {
    13 
    14         public void printMessage() {
    15 
    16             // 访问外部静态成员变量
    17             System.out.println("InnerStaticClass_static_msg: " + static_msg);
    18 
    19             // 编译报错,需要new一个外部类实例
    20            // System.out.println("InnerStaticClass_msg: " + OuterClass.msg);
    21 
    22 
    23             // 静态方法可以直接访问
    24             OuterClass.staticShow();
    25 
    26             // 非静态方法,不可以直接访问,需要new一个外部类实例
    27             OuterClass outerClass = new OuterClass();  // OuterClass.this.show();  // 'javap.loader.OuterClass.this' cannot be referenced from a static context
    28             outerClass.show();
    29 
    30         }
    31     }
    32     // 非静态内部类
    33     public class InnerClass{
    34         public void display(){
    35 
    36             // 访问外部静态成员变量
    37             System.out.println("Innerclass_static_msg1="+ OuterClass.static_msg); // 内部类访问外部类的静态属性,JVM会为外部类合成一个方法:static synthetic Method access$000:"()Ljava/lang/String;" 
    38 
    39             System.out.println("Innerclass_static_msg2="+ static_msg);
    40 
    41             // 编译报错
    42             // System.out.println("Innerclass_msg="+ OuterClass.msg);
    43 
    44 
    45             // 静态方法可以直接访问
    46             OuterClass.staticShow();  // 内部类调用外部类的静态方法void staticShow(),JVM会为外部类合成一个方法:static synthetic Method access$100:"()V"
    47 
    48             // 非静态方法,不可以直接访问,需要new一个外部类实例
    49             OuterClass outerClass = new OuterClass(); // 访问外部类非静态方法(属性),这样子再new一个外部类没必要,可以直接OuterClass.this.show() 或 OuterClass.this.msg
    50             outerClass.show(); // 内部类调用外部类的实例方法void show(),JVM会为外部类合成一个方法并定义为static,static synthetic Method access$200:"(Ljavap/loader/OuterClass;)V",因此需要传递参数(外部类对象)
    51         }
    52     }
    53 
    54     private static void staticShow() {
    55         System.out.println("out.staticShow()");
    56     }
    57 
    58     private void show() {
    59         System.out.println("out.show()");
    60     }
    61 }
    62 class Main
    63 {
    64     // 怎么创建静态内部类和非静态内部类的实例
    65     public static void main(String args[]){
    66         // 创建静态内部类的实例
    67         OuterClass.InnerStaticClass printer = new OuterClass.InnerStaticClass();
    68         // 调用静态内部类的非静态方法
    69         printer.printMessage();
    70 
    71         // 为了创建非静态内部类,我们需要外部类的实例
    72         OuterClass outer = new OuterClass();
    73         OuterClass.InnerClass inner = outer.new InnerClass();
    74         // 调用非静态内部类的非静态方法
    75         inner.display();
    76 
    77         // 我们也可以结合以上步骤,一步创建的内部类实例
    78         OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
    79         // 同样我们现在可以调用内部类方法
    80         innerObject.display();
    81     }
    82 }

    javac -g OuterClass.java后

    -rw-r--r--   1 ** staff   922 Nov 17 14:10 Outer.java
    -rw-r--r--   1 ** staff  1064 Nov 18 10:34 OuterClass$InnerClass.class
    -rw-r--r--   1 ** staff   991 Nov 18 10:34 OuterClass$InnerStaticClass.class
    -rw-r--r--   1 ** staff  1204 Nov 18 10:34 OuterClass.class

     java -jar ../asmtools.jar jdis OuterClass.class后

     1 package  javap/loader;
     2 
     3 super class OuterClass
     4         version 52:0
     5 {
     6 
     7 private static Field static_msg:"Ljava/lang/String;";
     8 private Field msg:"Ljava/lang/String;";
     9 
    10 Method "<init>":"()V"
    11         stack 2 locals 1
    12 {
    13                 aload_0;
    14                 invokespecial   Method java/lang/Object."<init>":"()V"; // 构造发
    15                 aload_0;
    16                 ldc     String "GeeksForGeeks_msg";
    17                 putfield        Field msg:"Ljava/lang/String;";
    18                 return;
    19         
    20 }
    21 
    22 private static Method staticShow:"()V"
    23         stack 2 locals 0
    24 {
    25                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    26                 ldc     String "out.staticShow()";
    27                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    28                 return;
    29 }
    30 
    31 private Method show:"()V"
    32         stack 2 locals 1
    33 {
    34                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    35                 ldc     String "out.show()";
    36                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    37                 return;
    38         
    39 }
    40 
    41 static synthetic Method access$000:"()Ljava/lang/String;"  // synthetic合成的,内部类访问外部类的静态属性(合成方法)
    42         stack 1 locals 0
    43 {
    44                 getstatic       Field static_msg:"Ljava/lang/String;";  // get静态属性
    45                 areturn;
    46 }
    47 
    48 static synthetic Method access$100:"()V"          // 内部类调用外部类的静态方法void staticShow()
    49         stack 0 locals 0
    50 {
    51                 invokestatic    Method staticShow:"()V";
    52                 return;
    53 }
    54 
    55 static synthetic Method access$200:"(Ljavap/loader/OuterClass;)V"    // 内部类调用外部类的实例方法void show(),JVM把它定义为static,因此需要传递参数(外部类对象
    56         stack 1 locals 1
    57 {
    58                 aload_0;
    59                 invokespecial   Method show:"()V";
    60                 return;
    61         
    62 }
    63 
    64 static Method "<clinit>":"()V"   
    65         stack 1 locals 0
    66 {
    67                 ldc     String "GeeksForGeeks_static_msg";   // clint 初始化静态代码(非final常量)
    68                 putstatic       Field static_msg:"Ljava/lang/String;";
    69                 return;
    70 }
    71 
    72 public InnerClass InnerClass=class OuterClass$InnerClass of class OuterClass;
    73 public static InnerClass InnerStaticClass=class OuterClass$InnerStaticClass of class OuterClass;
    74 
    75 } // end Class OuterClass

    java -jar ../asmtools.jar jdis OuterClass$InnerClass.class后

     1 package  javap/loader;
     2 
     3 super public class OuterClass$InnerClass
     4         version 52:0
     5 {
     6 
     7 final synthetic Field this$0:"Ljavap/loader/OuterClass;";  // 非静态内部类,合成的属性:外部类对象
     8 
     9 public Method "<init>":"(Ljavap/loader/OuterClass;)V"   // 非静态内部类的构造方法,JVM默认把外部类作为参数传递进来
    10         stack 2 locals 2
    11 {
    12                 aload_0;
    13                 aload_1;
    14                 putfield        Field this$0:"Ljavap/loader/OuterClass;";  // 把内部类的一个属性初始化为外部类的实例
    15                 aload_0;
    16                 invokespecial   Method java/lang/Object."<init>":"()V";
    17                 return;
    18         
    19 }
    20 
    21 public Method display:"()V"
    22         stack 3 locals 2
    23 {
    24                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    25                 new     class java/lang/StringBuilder;
    26                 dup;
    27                 invokespecial   Method java/lang/StringBuilder."<init>":"()V";
    28                 ldc     String "Innerclass_static_msg1=";
    29                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    30                 invokestatic    Method OuterClass.access$000:"()Ljava/lang/String;";    // 访问外部类的静态属性
    31                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    32                 invokevirtual   Method java/lang/StringBuilder.toString:"()Ljava/lang/String;";
    33                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    34                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    35                 new     class java/lang/StringBuilder;
    36                 dup;
    37                 invokespecial   Method java/lang/StringBuilder."<init>":"()V";
    38                 ldc     String "Innerclass_static_msg2=";
    39                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    40                 invokestatic    Method OuterClass.access$000:"()Ljava/lang/String;";
    41                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    42                 invokevirtual   Method java/lang/StringBuilder.toString:"()Ljava/lang/String;";
    43                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    44                 invokestatic    Method OuterClass.access$100:"()V";   // 调用外部类的静态方法void staticShow()
    45                 new     class OuterClass;
    46                 dup;
    47                 invokespecial   Method OuterClass."<init>":"()V";
    48                 astore_1;
    49                 aload_1;
    50                 invokestatic    Method OuterClass.access$200:"(Ljavap/loader/OuterClass;)V";  // 调用外部类的非静态方法void show(),实际上JVM把它编译为静态方法,参数为外部类对象(构造函数初始化过了)
    51                 return;
    52         
    53 }
    54 
    55 public InnerClass InnerClass=class OuterClass$InnerClass of class OuterClass;
    56 
    57 } // end Class OuterClass$InnerClass

    java -jar ../asmtools.jar jdis OuterClass$InnerStaticClass.class

     1 package  javap/loader;
     2 
     3 super public class OuterClass$InnerStaticClass
     4         version 52:0
     5 {
     6 
     7 
     8 public Method "<init>":"()V" // 静态内部类的构造方法参数没有外部类
     9         stack 1 locals 1
    10 {
    11                 aload_0;
    12                 invokespecial   Method java/lang/Object."<init>":"()V";
    13                 return;
    14         
    15 }
    16 
    17 public Method printMessage:"()V"
    18         stack 3 locals 2
    19 {
    20                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    21                 new     class java/lang/StringBuilder;
    22                 dup;
    23                 invokespecial   Method java/lang/StringBuilder."<init>":"()V";
    24                 ldc     String "InnerStaticClass_static_msg: ";
    25                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    26                 invokestatic    Method OuterClass.access$000:"()Ljava/lang/String;";
    27                 invokevirtual   Method java/lang/StringBuilder.append:"(Ljava/lang/String;)Ljava/lang/StringBuilder;";
    28                 invokevirtual   Method java/lang/StringBuilder.toString:"()Ljava/lang/String;";
    29                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    30                 invokestatic    Method OuterClass.access$100:"()V";
    31                 new     class OuterClass;
    32                 dup;
    33                 invokespecial   Method OuterClass."<init>":"()V";
    34                 astore_1;
    35                 aload_1;
    36                 invokestatic    Method OuterClass.access$200:"(Ljavap/loader/OuterClass;)V";
    37                 return;
    38         
    39 }
    40 
    41 public static InnerClass InnerStaticClass=class OuterClass$InnerStaticClass of class OuterClass;
    42 
    43 } // end Class OuterClass$InnerStaticClass

    java -jar ../asmtools.jar jdis Main.class

     1 package  javap/loader;
     2 
     3 super class Main
     4         version 52:0
     5 {
     6 
     7 
     8 Method "<init>":"()V"
     9         stack 1 locals 1
    10 {
    11                 aload_0;
    12                 invokespecial   Method java/lang/Object."<init>":"()V";
    13                 return;
    14         
    15 }
    16 
    17 public static Method main:"([Ljava/lang/String;)V"
    18         stack 4 locals 5
    19 {
    20                 new     class OuterClass$InnerStaticClass;
    21                 dup;
    22                 invokespecial   Method OuterClass$InnerStaticClass."<init>":"()V";  // 初始化静态内部类,JVM没有传递外部类
    23                 astore_1;
    24                 aload_1;
    25                 invokevirtual   Method OuterClass$InnerStaticClass.printMessage:"()V";
    26                 new     class OuterClass;
    27                 dup;
    28                 invokespecial   Method OuterClass."<init>":"()V";
    29                 astore_2;
    30                 new     class OuterClass$InnerClass;
    31                 dup;
    32                 aload_2;
    33                 dup;
    34                 invokevirtual   Method java/lang/Object.getClass:"()Ljava/lang/Class;";
    35                 pop;
    36                 invokespecial   Method OuterClass$InnerClass."<init>":"(Ljavap/loader/OuterClass;)V";  // 初始化非静态内部类,JVM默认把外部类作为参数传递
    37                 astore_3;
    38                 aload_3;
    39                 invokevirtual   Method OuterClass$InnerClass.display:"()V";
    40                 new     class OuterClass$InnerClass;
    41                 dup;
    42                 new     class OuterClass;
    43                 dup;
    44                 invokespecial   Method OuterClass."<init>":"()V";
    45                 dup;
    46                 invokevirtual   Method java/lang/Object.getClass:"()Ljava/lang/Class;";
    47                 pop;
    48                 invokespecial   Method OuterClass$InnerClass."<init>":"(Ljavap/loader/OuterClass;)V";
    49                 astore  4;
    50                 aload   4;
    51                 invokevirtual   Method OuterClass$InnerClass.display:"()V";
    52                 return;
    53         
    54 }
    55 
    56 public static InnerClass InnerStaticClass=class OuterClass$InnerStaticClass of class OuterClass;
    57 public InnerClass InnerClass=class OuterClass$InnerClass of class OuterClass;
    58 
    59 } // end Class Main

    二、匿名类字节码XXX$1.class

    例子2:匿名类(比如如下的Runnable,直接接口实现好),编译后会生成NiMingClass$1.class

     1 package javap.loader;
     2 
     3 public class NiMingClass {
     4 
     5     private int foo;
     6 
     7     public void test() {
     8         Runnable r = new Runnable() {
     9             public void run() {
    10                 System.out.println(foo);  // 内部类访问外部类的非静态属性,JVM会为外部类生成一个方法 static synthetic Method access$000:"(Ljavap/loader/NiMingClass;)I"
    11             }
    12         };
    13     }
    14 }

    javac -g NiMingClass.java

    1 -rw-r--r--   1 **  staff   767 Nov 18 11:25 NiMingClass$1.class
    2 -rw-r--r--   1 **  staff   642 Nov 18 11:25 NiMingClass.class
    3 -rw-r--r--   1 ** staff   242 Nov 18 11:25 NiMingClass.java

    反编译结果:

    java -jar ../asmtools.jar jdis  NiMingClass.class

     1 package  javap/loader;
     2 
     3 super public class NiMingClass
     4         version 52:0
     5 {
     6 
     7 private Field foo:I;
     8 
     9 public Method "<init>":"()V"
    10         stack 1 locals 1
    11 {
    12                 aload_0;
    13                 invokespecial   Method java/lang/Object."<init>":"()V";
    14                 return;
    15         
    16 }
    17 
    18 public Method test:"()V"
    19         stack 3 locals 2
    20 {
    21                 new     class NiMingClass$1;
    22                 dup;
    23                 aload_0;
    24                 invokespecial   Method NiMingClass$1."<init>":"(Ljavap/loader/NiMingClass;)V";  // 初始化匿名内部类
    25                 astore_1;
    26                 return;
    27         
    28 }
    29 
    30 static synthetic Method access$000:"(Ljavap/loader/NiMingClass;)I"  //内部类访问外部类的属性,JVM会为其生成一个静态方法
    31         stack 1 locals 1
    32 {
    33                 aload_0;
    34                 getfield        Field foo:"I";
    35                 ireturn;
    36         
    37 }
    38 
    39 InnerClass class NiMingClass$1;
    40 
    41 } // end Class NiMingClass

     java -jar ../asmtools.jar jdis  NiMingClass$1.class

     1 package  javap/loader;
     2 
     3 super class NiMingClass$1  //匿名类生成
     4         implements java/lang/Runnable
     5         version 52:0
     6 {
     7 
     8 final synthetic Field this$0:"Ljavap/loader/NiMingClass;";  // 生成一个外部类对象的属性
     9 
    10 Method "<init>":"(Ljavap/loader/NiMingClass;)V"
    11         stack 2 locals 2
    12 {
    13                 aload_0;
    14                 aload_1;
    15                 putfield        Field this$0:"Ljavap/loader/NiMingClass;";  // 初始化属性(即外部类对象)
    16                 aload_0;
    17                 invokespecial   Method java/lang/Object."<init>":"()V";
    18                 return;
    19         
    20 }
    21 
    22 public Method run:"()V"
    23         stack 2 locals 1
    24 {
    25                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    26                 aload_0;
    27                 getfield        Field this$0:"Ljavap/loader/NiMingClass;";
    28                 invokestatic    Method NiMingClass.access$000:"(Ljavap/loader/NiMingClass;)I";  // 访问外部类的foo属性(非静态)
    29                 invokevirtual   Method java/io/PrintStream.println:"(I)V";
    30                 return;
    31         
    32 }
    33 
    34 InnerClass class NiMingClass$1;
    35 
    36 } // end Class NiMingClass$1

     三、调用内部类的private构造方法,会生成字节码XXX$1.class

    3.1 基本情况

    例子3-1:

    package javap.loader;
    
    public class TestJavac {
        void Test() {
            innerClass lklk = new innerClass();  // 没法直接调用private构造方法,所以JVM会生成一个匿名内部类TestJavac$1,初始化的时候先调用TestJavac$1,TestJava$1内部再调用内部类的private构造方法
            lklk.biubiu();
        }
    
        private class innerClass {
            private innerClass() {  
                // TODO 自动生成的构造函数存根
            }
    
            void biubiu() {
                System.out.println("XXXX");
            }
        }
    }

    结果:

    1 -rw-r--r--   1 **  staff   201 Nov 18 11:03 TestJavac$1.class
    2 -rw-r--r--   1 **  staff   909 Nov 18 11:03 TestJavac$innerClass.class
    3 -rw-r--r--   1 **  staff   625 Nov 18 11:03 TestJavac.class
    4 -rw-r--r--   1 **  staff   349 Nov 18 11:03 TestJavac.java

    反编译看下各个字节码文件:

    java -jar ../asmtools.jar jdis TestJavac.class

     1 package  javap/loader;
     2 
     3 super public class TestJavac
     4         version 52:0
     5 {
     6 
     7 
     8 public Method "<init>":"()V"
     9         stack 1 locals 1
    10 {
    11                 aload_0;
    12                 invokespecial   Method java/lang/Object."<init>":"()V";
    13                 return;
    14         
    15 }
    16 
    17 Method Test:"()V"
    18         stack 4 locals 2
    19 {
    20                 new     class TestJavac$innerClass;
    21                 dup;
    22                 aload_0;
    23                 aconst_null;
    24                 invokespecial   Method TestJavac$innerClass."<init>":"(Ljavap/loader/TestJavac;Ljavap/loader/TestJavac$1;)V";
    25                 astore_1;
    26                 aload_1;
    27                 invokevirtual   Method TestJavac$innerClass.biubiu:"()V";
    28                 return;
    29         
    30 }
    31 
    32 static synthetic InnerClass class TestJavac$1;
    33 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    34 
    35 } // end Class TestJavac

     java -jar ../asmtools.jar jdis TestJavac$innerClass.class

     1 package  javap/loader;
     2 
     3 super class TestJavac$innerClass
     4         version 52:0
     5 {
     6 
     7 final synthetic Field this$0:"Ljavap/loader/TestJavac;";
     8 
     9 private Method "<init>":"(Ljavap/loader/TestJavac;)V"
    10         stack 2 locals 2
    11 {
    12                 aload_0;
    13                 aload_1;
    14                 putfield        Field this$0:"Ljavap/loader/TestJavac;";
    15                 aload_0;
    16                 invokespecial   Method java/lang/Object."<init>":"()V";
    17                 return;
    18         
    19 }
    20 
    21 Method biubiu:"()V"
    22         stack 2 locals 1
    23 {
    24                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    25                 ldc     String "XXXX";
    26                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    27                 return;
    28         
    29 }
    30 
    31 synthetic Method "<init>":"(Ljavap/loader/TestJavac;Ljavap/loader/TestJavac$1;)V"  // JVM生成的构造方法,内部再去调用内部类的private构造方法
    32         stack 2 locals 3
    33 {
    34                 aload_0;
    35                 aload_1;
    36                 invokespecial   Method "<init>":"(Ljavap/loader/TestJavac;)V";
    37                 return;
    38         
    39 }
    40 
    41 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    42 static synthetic InnerClass class TestJavac$1;
    43 
    44 } // end Class TestJavac$innerClass

    java -jar ../asmtools.jar jdis TestJavac$1.class

    1 package  javap/loader;
    2 
    3 super synthetic class TestJavac$1
    4         version 52:0
    5 {
    6 
    7 static synthetic InnerClass class TestJavac$1;
    8 
    9 } // end Class TestJavac$1

    例子3-2: 

     1 package javap.loader;
     2 
     3 public class TestJavac {
     4     void Test() {
     5         // 注释掉如下两行,重新执行javac,不再生成 TestJavac$1.class
     6         // 调用public构造函数,则不会生成匿名内部类TestJavac$1.class(调用private构造函数,才会生成TestJavac$1.class)
     7         innerClass lklk = new innerClass();
     8         lklk.biubiu();
     9     }
    10 
    11     private class innerClass {
    12         public innerClass() { 
    13             // TODO 自动生成的构造函数存根
    14         }
    15 
    16         void biubiu() {
    17             System.out.println("XXXX");
    18         }
    19     }
    20 }

    javac -g TestJavac.java   // 无TestJavac$1.class

    1 -rw-r--r--   1 **  staff   684 Nov 18 15:23 TestJavac$innerClass.class
    2 -rw-r--r--   1 **  staff   560 Nov 18 15:23 TestJavac.class
    3 -rw-r--r--   1 **  staff   581 Nov 18 15:22 TestJavac.java

    反编译后查看结果:

    java -jar ../asmtools.jar jdis  TestJavac.class

     1 package  javap/loader;
     2 
     3 super public class TestJavac
     4         version 52:0
     5 {
     6 
     7 
     8 public Method "<init>":"()V"
     9         stack 1 locals 1
    10 {
    11                 aload_0;
    12                 invokespecial   Method java/lang/Object."<init>":"()V";
    13                 return;
    14         
    15 }
    16 
    17 Method Test:"()V"
    18         stack 3 locals 2
    19 {
    20                 new     class TestJavac$innerClass;
    21                 dup;
    22                 aload_0;
    23                 invokespecial   Method TestJavac$innerClass."<init>":"(Ljavap/loader/TestJavac;)V";
    24                 astore_1;
    25                 aload_1;
    26                 invokevirtual   Method TestJavac$innerClass.biubiu:"()V";
    27                 return;
    28         
    29 }
    30 
    31 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    32 
    33 } // end Class TestJavac

     java -jar ../asmtools.jar jdis  TestJavac$innerClass.class

     1 package  javap/loader;
     2 
     3 super class TestJavac$innerClass
     4         version 52:0
     5 {
     6 
     7 final synthetic Field this$0:"Ljavap/loader/TestJavac;";
     8 
     9 public Method "<init>":"(Ljavap/loader/TestJavac;)V"
    10         stack 2 locals 2
    11 {
    12                 aload_0;
    13                 aload_1;
    14                 putfield        Field this$0:"Ljavap/loader/TestJavac;";
    15                 aload_0;
    16                 invokespecial   Method java/lang/Object."<init>":"()V";
    17                 return;
    18         
    19 }
    20 
    21 Method biubiu:"()V"
    22         stack 2 locals 1
    23 {
    24                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    25                 ldc     String "XXXX";
    26                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    27                 return;
    28         
    29 }
    30 
    31 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    32 
    33 } // end Class TestJavac$innerClass

    例子3-3:

     1 package javap.loader;
     2 
     3 public class TestJavac {
     4     void Test() {
     5         // 注释掉如下两行,重新执行javac,不再生成 TestJavac$1.class
     6       /*  innerClass lklk = new innerClass();
     7         lklk.biubiu();*/
     8     }
     9 
    10     private class innerClass {
    11         private innerClass() {
    12             // TODO 自动生成的构造函数存根
    13         }
    14 
    15         void biubiu() {
    16             System.out.println("XXXX");
    17         }
    18     }
    19 }

    javac -g TestJavac.java

    1 -rw-r--r--   1 **  staff   684 Nov 18 11:17 TestJavac$innerClass.class
    2 -rw-r--r--   1 **  staff   425 Nov 18 11:17 TestJavac.class
    3 -rw-r--r--   1 ** staff   439 Nov 18 11:16 TestJavac.java

    反编译结果:

    java -jar ../asmtools.jar jdis TestJavac.class

     1 package  javap/loader;
     2 
     3 super public class TestJavac
     4         version 52:0
     5 {
     6 
     7 
     8 public Method "<init>":"()V"
     9         stack 1 locals 1
    10 {
    11                 aload_0;
    12                 invokespecial   Method java/lang/Object."<init>":"()V";
    13                 return;
    14         
    15 }
    16 
    17 Method Test:"()V"
    18         stack 0 locals 1
    19 {
    20                 return;
    21         
    22 }
    23 
    24 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    25 
    26 } // end Class TestJavac

    java -jar ../asmtools.jar jdis TestJavac$innerClass.class

     1 package  javap/loader;
     2 
     3 super class TestJavac$innerClass
     4         version 52:0
     5 {
     6 
     7 final synthetic Field this$0:"Ljavap/loader/TestJavac;";
     8 
     9 private Method "<init>":"(Ljavap/loader/TestJavac;)V"
    10         stack 2 locals 2
    11 {
    12                 aload_0;
    13                 aload_1;
    14                 putfield        Field this$0:"Ljavap/loader/TestJavac;";
    15                 aload_0;
    16                 invokespecial   Method java/lang/Object."<init>":"()V";
    17                 return;
    18         
    19 }
    20 
    21 Method biubiu:"()V"
    22         stack 2 locals 1
    23 {
    24                 getstatic       Field java/lang/System.out:"Ljava/io/PrintStream;";
    25                 ldc     String "XXXX";
    26                 invokevirtual   Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
    27                 return;
    28         
    29 }
    30 
    31 private InnerClass innerClass=class TestJavac$innerClass of class TestJavac;
    32 
    33 } // end Class TestJavac$innerClass

    3.2 java -verbose:class分析运行时是否加载XXX$1.class

    例子3-4:

    • 反编译后出现TestJavac$1.class,但是java -verbose:class运行时未加载TestJavac$1.class,看反编译后的代码调用内部类的private构造函数时候应该是通过TestJavac$1.class中转的,但是为何不加载TestJavac$1.class,可能是JVM内部的一种实现
    • 后面再看例3-5:java -verbose:class 运行时会加载 NiMingClass$1.class,因为这种情况是一个匿名内部类,要调用它初始化
     1 package javap.loader;
     2 
     3 public class TestJavac {
     4     void Test() {
     5         // 注释掉如下两行,重新执行javac,不再生成 TestJavac$1.class
     6         // 调用public构造函数,则不会生成匿名内部类TestJavac$1.class(调用private构造函数,才会生成TestJavac$1.class)
     7         innerClass lklk = new innerClass();
     8         lklk.biubiu();
     9     }
    10 
    11     private class innerClass {
    12         private innerClass() {
    13             // TODO 自动生成的构造函数存根
    14         }
    15 
    16         void biubiu() {
    17             System.out.println("XXXX");
    18         }
    19     }
    20 
    21     public static void main(String[] args) {
    22         TestJavac testJavac = new TestJavac();
    23         testJavac.Test();
    24     }
    25 }

     java -verbose:class javap.loader.TestJavac

     1 $ java -verbose:class javap.loader.TestJavac
     2 [Opened /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     3 [Loaded java.lang.Object from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     4 [Loaded java.io.Serializable from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     5 [Loaded java.lang.Comparable from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     6 [Loaded java.lang.CharSequence from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     7 [Loaded java.lang.String from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
     8 ************(省略)
     9 [Loaded java.security.BasicPermissionCollection from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
    10 [Loaded javap.loader.TestJavac from file:/Users/xx/work/code/testDemo/src/main/java/]
    11 [Loaded sun.launcher.LauncherHelper$FXHelper from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
    12 [Loaded java.lang.Class$MethodArray from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
    13 [Loaded java.lang.Void from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
    14 [Loaded javap.loader.TestJavac$innerClass from file:/Users/xx/work/code/testDemo/src/main/java/]
    15 XXXX  // biubiu打印的结果
    16 [Loaded java.lang.Shutdown from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]
    17 [Loaded java.lang.Shutdown$Lock from /Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home/jre/lib/rt.jar]

    例子3-5:

     1 package javap.loader;
     2 
     3 public class NiMingClass {
     4 
     5     private static int foo = 9;
     6 
     7     public static void test() {
     8         Runnable r = new Runnable() {
     9             public void run() {
    10                 System.out.println(foo);
    11             }
    12         };
    13     }
    14 
    15     public static void main(String[] args) {
    16         test();
    17     }
    18 }

     四、静态内部类使用场景(如Builder模式)

    附:java静态类

    • 静态内部类使用场景一般是当外部类需要使用内部类,而内部类无需外部类资源,并且内部类可以单独创建的时候会考虑采用静态内部类的设计
      • // 静态内部类
        Inner i = new Outer.Inner();

         // 普通内部类

        Outer o = new Outer();
        Inner i = o.new Inner();
          
    • Builder模式:
      • 1.如果类的构造器或静态工厂中有多个参数,设计这样类时,最好使用Builder模式,特别是当大多数参数都是可选的时候。
      • 2.如果现在不能确定参数的个数,最好一开始就使用构建器即Builder模式。
    •  1 public class Outer {
       2     private String name;
       3     private int age;
       4 
       5     public static class Builder {
       6         private String name;
       7         private int age;
       8 
       9         public Builder() {
      10         }
      11 
      12         public Builder withName(String name) {
      13             this.name = name;
      14             return this;
      15         }
      16 
      17         public Builder withAge(int age) {
      18             this.age = age;
      19             return this;
      20         }
      21 
      22         public Outer build() {
      23             return new Outer(this);  // 调用外部的构造函数
      24         }
      25     }
      26 
      27     private Outer(Builder b) {  // private
      28         this.age = b.age;
      29         this.name = b.name;
      30     }
      31 }

      初始化:

          Outer outer = new Outer.Builder().withName("Yang Liu").withAge(2).build();
  • 相关阅读:
    Webapi通过报文获取post上来的数据
    Jquery的跨域调用
    @html.ActionLink的几种参数格式
    MVC中使用RadioButtonFor
    string、Empty和null三者的区别
    JQuery中$.ajax()方法参数详解
    多线程与异步的区别
    IEnumerable,ICollection,IList,List之间的区别
    win10锁屏或睡眠一段时间后弹不出登录框
    ssh简明安全规划
  • 原文地址:https://www.cnblogs.com/wxdlut/p/13998601.html
Copyright © 2011-2022 走看看