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

  • 外部类使用 内部类:

    • 非静态内部类:

      • 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-内部类分析的更多相关文章

  1. JVM性能分析与优化

    JVM性能分析与优化: http://www.docin.com/p-757199232.html

  2. 大数据学习--day13(字符串String--源码分析--JVM内存分析)

    字符串String--源码分析--JVM内存分析 String 类的对象 , 是不可变的字符串对象呢 这个不可变很重要,之后要讲的intern()也离不开它的不可变性. https://www.cnb ...

  3. UAVStack JVM监控分析工具:图形化展示采集及分析监控数据

    摘要:UAVStack推出的JVM监控分析工具提供基于页面的展现方式,以图形化的方式展示采集到的监控数据:同时提供JVM基本参数获取.内存dump.线程分析.内存分配采样和热点方法分析等功能. 引言 ...

  4. 学习记录--JVM内存分析

    今天刷牛客网的题时,看到了两位大神关于JVM内存分析的讲解,就顺手记录学习一下. JVM内存模型图 方法区域存放了所加载的类的信息(名称.修饰符等).类中的静态变量.类中定义为final类型的常量.类 ...

  5. JVM常见问题分析

    JVM常见问题分析 启动,并且去查看日志 ./startup.sh && tail -f ../logs/catalina.out 常见有有以下几个问题: 1.java.lang.Ou ...

  6. 全网最硬核 JVM TLAB 分析(单篇版不包含额外加菜)

    今天,又是干货满满的一天.这是全网最硬核 JVM 系列的开篇,首先从 TLAB 开始.由于文章很长,每个人阅读习惯不同,所以特此拆成单篇版和多篇版 全网最硬核 JVM TLAB 分析(单篇版不包含额外 ...

  7. Day05_22_实例化对象的JVM内存分析

    创建对象的 JVM 内存分析 *new 运算符的作用是创建对象,在JVM堆内存中开辟新的内存空间 *方法区内存:在类加载的时候,class字节码文件被加载到该内存空间当中 *栈内存(局部变量):方法代 ...

  8. JVM内存分析

    1.java内存模型分析 java虚拟机运行时数据存储区域包括线程隔离和线程共享两类,整个PC的内存图如下所示: 下面对以上内存区域说明: 1.1 register和cache 当代计算机一般有多个c ...

  9. 利用MAT玩转JVM内存分析(一)

    本文首发于公众号:javaadu 尽管JVM提供了自动内存管理的机制,试图降低程序员的开发门槛,确实也实现了这一目标,在日常开发中,我们一般都不需要关心对象的内存释放.JVM大部分都是使用trace算 ...

  10. JVM逃逸分析

    开启逃逸分析: -server -XX:+DoEscapeAnalysis -XX:+PrintGCDetail -Xmx10m -Xms10m 关闭逃逸分析: -server -XX:-DoEsca ...

随机推荐

  1. 初始elasticSearch

    elasticSearch 大致印象 为什么用? mysql更擅长于crud等操作,当一张表达到百万级别时,检索速度过慢 es检索速度快 基本概念 Index索引(两层意思) 动词:类似mysql的i ...

  2. VuePress@next 使用数学公式插件

    VuePress@next 使用数学公式插件 搞了一个VuePress1.0的 现在升级了一下,但是使用数学公式的插件老报错啊!经过不懈努力,终于搞定了.现在记录一下. VuePress 介绍 Vue ...

  3. 《深入理解Java虚拟机》读书笔记: 类加载器

                                                             类加载器   虚拟机设计团队把类加载阶段中的"通过一个类的全限定名来获取描述 ...

  4. AI绘画StableDiffusion实操教程:可爱头像奶茶小女孩(附高清图片)

    本教程收集于:AIGC从入门到精通教程汇总 今天继续分享AI绘画实操教程,如何用lora包生成超可爱头像奶茶小女孩 放大高清图已放到教程包内,需要的可以自取. 欢迎来到我们这篇特别的文章--<A ...

  5. 《SQL与数据库基础》15. 触发器

    目录 触发器 语法 示例-insert型触发器 示例-update型触发器 示例-delete型触发器 本文以 MySQL 为例 触发器 触发器是与表有关的数据库对象,指在 insert/update ...

  6. 《CTFshow-Web入门》03. Web 21~30

    @ 目录 web21 题解 原理 web22 题解 原理 web23 题解 原理 web24 题解 原理 web25 题解 原理 web26 题解 web27 题解 web28 题解 web29 题解 ...

  7. gitlab与LDAP 联调

    gitlab整理 目录 gitlab整理 1.安装Gitlab依赖包 2.下载,安装 3.配置,访问域名及邮箱 4.初始化,启动 5.访问,以及邮箱测试 5.1汉化 6.问题总结处理 6.1安装时出现 ...

  8. vue3.3.x setup 新实验性特性 defineModel 定义多个属性

    由于有些业务组件需要定义多个响应式props,类似这种(比较懒,没上ts),在vue3.3.x以前,如果不用三方库,代码会变得很繁琐 <script setup> const props ...

  9. Gradle 设置全局镜像源

    复制 init.gradle.kts 文件到 Windows 的 %USERPROFILE%/.gradle 或者 Linux 的 ~/.gradle 目录下.也可以直接复制文末的代码为 init.g ...

  10. c++枚举详细介绍以及具体用法

    C++ 中的枚举(Enumeration)是一种用于定义命名常量集合的数据类型.枚举可以提高代码的可读性和可维护性,让您可以使用有意义的名称来表示特定的取值,而不必使用原始的数字常量. 枚举的基本语法 ...