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

  • 外部类使用 内部类:

    • 非静态内部类:

      • 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. PhotoShop AI 爱国版保姆级安装和使用

    上篇Photoshop AI 令人惊叹的生成式填充介绍了 PhotoShop AI 的新特性功能,有人以为我收了 Adobe 公司的钱帮它们做推广~~~.别不信,事实上确有其事,某平台审核直接把它删掉 ...

  2. 初始elasticSearch

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

  3. c语言分析和循坏对应的汇编定义格式(Debug版本)

    c语言if单分支结构所对应的汇编代码结构 #include "stdafx.h" int main(int argc, char* argv[]) { if(argc > 8 ...

  4. Element-ui源码解析(一):项目目录解析

    开始看原码了,我们要开始一些准备工作, 既然是拆代码,那么我们要先把代码搞到手 1.如何下载原码  随便开个项目 npm i element-ui -S 将源码下载到本地 随后在node_module ...

  5. 一个批处理,解决你重装python第三方模块的烦恼~(1.0版本)

    @echo offpip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simplepython -m pip insta ...

  6. Django: AttributeError: 'str' object has no attribute 'decode'

    Django安装Mysql驱动 pip install PyMySQL 在Django的工程同名子目录的__init__.py文件中添加如下语句 from pymysql import install ...

  7. linux基础:编译

    程序编译 在linux中,gnu项目提供了gcc编译器.g++编译器和gdb调试器. C和C++语言正在不断发展,为了保持兼容程序语言的最新特性,开发者通常选择GCC来编译C语言编写的源代码,选择G+ ...

  8. 从零开始实现放置游戏(十七)——完结篇(附DEMO地址)

    大家好,时隔2年多,我来填坑啦! 之前用的技术.设计思路都不成熟,所以直接干掉重做了. 由于从头教学实在太啰嗦,精力也有限,咱们还是直接上源码吧. DEMO地址: http://212.129.154 ...

  9. 《深入理解Java虚拟机》读书笔记:方法调用

      方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程.在程序运行时,进行方法调用是最普遍.最频繁的操作,但前面已经讲过 ...

  10. P1551 亲戚 && #569. 【例4-7】亲戚(并查集)

    P1551 亲戚 题目链接:落谷 题目链接:TFLS OJ 落谷题解(具体分析见慎入潜出P239) #include<bits/stdc++.h> using namespace std; ...