JVM之Synthetic

发布于:2024-12-07 ⋅ 阅读:(99) ⋅ 点赞:(0)

Synthetic是人造,合成的意思,在虚拟机很多地方使用ACC_SYNTHETIC表示编译器自动生成的,区别于我们自己写的程序代码。这样说可能比较模糊,我们举个例子:我们创建一个内部类,如下

public class TestInnerClass {

    public void say(String msg) {
        System.out.println(msg);
    }

    class InnerClass {
        public void sayInner() {
            say("hello");
        }
    }
}

我们用javap看一下内部类InnerClass反编译之后的情况:

完整如下:

Classfile /F:/demo/mallsystem/provider/target/classes/com/mall/test/TestInnerClass$InnerClass.class
  Last modified 2024-11-28; size 638 bytes
  MD5 checksum 9f5efd7b8d0ad50545773d2a0e198f60
  Compiled from "TestInnerClass.java"
class com.mall.test.TestInnerClass$InnerClass
  minor version: 0
  major version: 52
  flags: ACC_SUPER
Constant pool:
   #1 = Fieldref           #5.#22         // com/mall/test/TestInnerClass$InnerClass.this$0:Lcom/mall/test/TestInnerClass;
   #2 = Methodref          #6.#23         // java/lang/Object."<init>":()V
   #3 = String             #24            // hello
   #4 = Methodref          #25.#26        // com/mall/test/TestInnerClass.say:(Ljava/lang/String;)V
   #5 = Class              #27            // com/mall/test/TestInnerClass$InnerClass
   #6 = Class              #28            // java/lang/Object
   #7 = Utf8               this$0
   #8 = Utf8               Lcom/mall/test/TestInnerClass;
   #9 = Utf8               <init>
  #10 = Utf8               (Lcom/mall/test/TestInnerClass;)V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               InnerClass
  #16 = Utf8               InnerClasses
  #17 = Utf8               Lcom/mall/test/TestInnerClass$InnerClass;
  #18 = Utf8               sayInner
  #19 = Utf8               ()V
  #20 = Utf8               SourceFile
  #21 = Utf8               TestInnerClass.java
  #22 = NameAndType        #7:#8          // this$0:Lcom/mall/test/TestInnerClass;
  #23 = NameAndType        #9:#19         // "<init>":()V
  #24 = Utf8               hello
  #25 = Class              #29            // com/mall/test/TestInnerClass
  #26 = NameAndType        #30:#31        // say:(Ljava/lang/String;)V
  #27 = Utf8               com/mall/test/TestInnerClass$InnerClass
  #28 = Utf8               java/lang/Object
  #29 = Utf8               com/mall/test/TestInnerClass
  #30 = Utf8               say
  #31 = Utf8               (Ljava/lang/String;)V
{
  final com.mall.test.TestInnerClass this$0;
    descriptor: Lcom/mall/test/TestInnerClass;
    flags: ACC_FINAL, ACC_SYNTHETIC

  com.mall.test.TestInnerClass$InnerClass(com.mall.test.TestInnerClass);
    descriptor: (Lcom/mall/test/TestInnerClass;)V
    flags:
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: putfield      #1                  // Field this$0:Lcom/mall/test/TestInnerClass;
         5: aload_0
         6: invokespecial #2                  // Method java/lang/Object."<init>":()V
         9: return
      LineNumberTable:
        line 12: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/mall/test/TestInnerClass$InnerClass;
            0      10     1 this$0   Lcom/mall/test/TestInnerClass;

  public void sayInner();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #1                  // Field this$0:Lcom/mall/test/TestInnerClass;
         4: ldc           #3                  // String hello
         6: invokevirtual #4                  // Method com/mall/test/TestInnerClass.say:(Ljava/lang/String;)V
         9: return
      LineNumberTable:
        line 14: 0
        line 15: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/mall/test/TestInnerClass$InnerClass;
}
SourceFile: "TestInnerClass.java"
InnerClasses:
     #15= #5 of #25; //InnerClass=class com/mall/test/TestInnerClass$InnerClass of class com/mall/test/TestInnerClass

重点看下面标记的,ACC_SYNTHETIC标记出现了

这里编译器在内部类生成了一个TestInnerClass的引用对象this$0,因为是编译器自动合成的,所以标记了ACC_SYNTHETIC。

而下面是内部类的构造方法,可以看到它传入了外部类的实例对象,之后把它赋值给this$0

aload_0默认是实例方法第一个参数是this,即内部类自己的引用

aload_1则是加载第一个入参也就是外部类实例对象

putfield #1就是把外部实例设置给this$0

所以这也就解释了为什么内部类创建需要外部类对象创建了,如果外部类对象还没有生成,怎么传给内部类的构造方法呢?

而我们内部类能调用外部类的方法,也正是通过外部类的实例对象调用的


网站公告

今日签到

点亮在社区的每一天
去签到