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();

posted on 2020-11-18 10:54  gogoy  阅读(168)  评论(0编辑  收藏  举报

导航