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();
JVM-内部类分析的更多相关文章
- JVM性能分析与优化
JVM性能分析与优化: http://www.docin.com/p-757199232.html
- 大数据学习--day13(字符串String--源码分析--JVM内存分析)
字符串String--源码分析--JVM内存分析 String 类的对象 , 是不可变的字符串对象呢 这个不可变很重要,之后要讲的intern()也离不开它的不可变性. https://www.cnb ...
- UAVStack JVM监控分析工具:图形化展示采集及分析监控数据
摘要:UAVStack推出的JVM监控分析工具提供基于页面的展现方式,以图形化的方式展示采集到的监控数据:同时提供JVM基本参数获取.内存dump.线程分析.内存分配采样和热点方法分析等功能. 引言 ...
- 学习记录--JVM内存分析
今天刷牛客网的题时,看到了两位大神关于JVM内存分析的讲解,就顺手记录学习一下. JVM内存模型图 方法区域存放了所加载的类的信息(名称.修饰符等).类中的静态变量.类中定义为final类型的常量.类 ...
- JVM常见问题分析
JVM常见问题分析 启动,并且去查看日志 ./startup.sh && tail -f ../logs/catalina.out 常见有有以下几个问题: 1.java.lang.Ou ...
- 全网最硬核 JVM TLAB 分析(单篇版不包含额外加菜)
今天,又是干货满满的一天.这是全网最硬核 JVM 系列的开篇,首先从 TLAB 开始.由于文章很长,每个人阅读习惯不同,所以特此拆成单篇版和多篇版 全网最硬核 JVM TLAB 分析(单篇版不包含额外 ...
- Day05_22_实例化对象的JVM内存分析
创建对象的 JVM 内存分析 *new 运算符的作用是创建对象,在JVM堆内存中开辟新的内存空间 *方法区内存:在类加载的时候,class字节码文件被加载到该内存空间当中 *栈内存(局部变量):方法代 ...
- JVM内存分析
1.java内存模型分析 java虚拟机运行时数据存储区域包括线程隔离和线程共享两类,整个PC的内存图如下所示: 下面对以上内存区域说明: 1.1 register和cache 当代计算机一般有多个c ...
- 利用MAT玩转JVM内存分析(一)
本文首发于公众号:javaadu 尽管JVM提供了自动内存管理的机制,试图降低程序员的开发门槛,确实也实现了这一目标,在日常开发中,我们一般都不需要关心对象的内存释放.JVM大部分都是使用trace算 ...
- JVM逃逸分析
开启逃逸分析: -server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m 关闭逃逸分析: -server -XX:-DoEsca ...
随机推荐
- PhotoShop AI 爱国版保姆级安装和使用
上篇Photoshop AI 令人惊叹的生成式填充介绍了 PhotoShop AI 的新特性功能,有人以为我收了 Adobe 公司的钱帮它们做推广~~~.别不信,事实上确有其事,某平台审核直接把它删掉 ...
- 初始elasticSearch
elasticSearch 大致印象 为什么用? mysql更擅长于crud等操作,当一张表达到百万级别时,检索速度过慢 es检索速度快 基本概念 Index索引(两层意思) 动词:类似mysql的i ...
- c语言分析和循坏对应的汇编定义格式(Debug版本)
c语言if单分支结构所对应的汇编代码结构 #include "stdafx.h" int main(int argc, char* argv[]) { if(argc > 8 ...
- Element-ui源码解析(一):项目目录解析
开始看原码了,我们要开始一些准备工作, 既然是拆代码,那么我们要先把代码搞到手 1.如何下载原码 随便开个项目 npm i element-ui -S 将源码下载到本地 随后在node_module ...
- 一个批处理,解决你重装python第三方模块的烦恼~(1.0版本)
@echo offpip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simplepython -m pip insta ...
- Django: AttributeError: 'str' object has no attribute 'decode'
Django安装Mysql驱动 pip install PyMySQL 在Django的工程同名子目录的__init__.py文件中添加如下语句 from pymysql import install ...
- linux基础:编译
程序编译 在linux中,gnu项目提供了gcc编译器.g++编译器和gdb调试器. C和C++语言正在不断发展,为了保持兼容程序语言的最新特性,开发者通常选择GCC来编译C语言编写的源代码,选择G+ ...
- 从零开始实现放置游戏(十七)——完结篇(附DEMO地址)
大家好,时隔2年多,我来填坑啦! 之前用的技术.设计思路都不成熟,所以直接干掉重做了. 由于从头教学实在太啰嗦,精力也有限,咱们还是直接上源码吧. DEMO地址: http://212.129.154 ...
- 《深入理解Java虚拟机》读书笔记:方法调用
方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程.在程序运行时,进行方法调用是最普遍.最频繁的操作,但前面已经讲过 ...
- P1551 亲戚 && #569. 【例4-7】亲戚(并查集)
P1551 亲戚 题目链接:落谷 题目链接:TFLS OJ 落谷题解(具体分析见慎入潜出P239) #include<bits/stdc++.h> using namespace std; ...