一、内部类和外部类调用及字节码解释
- 外部类使用 内部类:
- 非静态内部类:
- 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();