Java冷知识(三)编译器的花招之synthetic

我们在阅读JDK反射包源码时,会遇到isSynthetic()方法,其实现之一是Modifier.isSynthetic(getModifiers()),其他方式的原理一样。Modifier是专门定义修饰符的类,其中static final int SYNTHETIC = 0x00001000 表名synthetic是修饰符的一种。
我尝试用synthetic来修饰自定义的Class/Field/Method/Constructer。但是都会编译失败,理由是不认识synthetic修饰符。那么synthetic到底是怎么使用的呢?

官方定义

我从Java语言规范中找到了定义:
Any constructs introduced by the compiler that do not have a corresponding construct in the source code must be marked as synthetic ,except for default constructs and the class initialization method.
意思大概是这样:任何被编译器引入的构造器在源代码中没有一个相应的构造器,那么该段代码就必须要被标记为synthetic的(复合的),除了默认的构造器和类初始化方法。

验证

基于上面的定义,我们知道synthetic是由编译器生成的,而且synthetic有复合的、合成的意思。所以猜测是否是用在内部类中的。我们先构造一个内部类:

public  class SyntheticDemo {

    public static void main(String[] args) {

        InnerClass innerObject = new InnerClass();
        System.out.println("inner: " + innerObject.inner);
    }

    private static class InnerClass{

        private String inner = "我在内部";
    }
}

编译后生成了三个文件:

  • SyntheticDemo$1.class
  • SyntheticDemo$InnerClass.class
  • SyntheticDemo.class

我们依次反编译一下这三个class文件

SyntheticDemo$1.class

javap SyntheticDemo$1.class:

Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$1 {
}

javap -v SyntheticDemo$1.class

  Last modified 2019-12-12; size 205 bytes
  MD5 checksum 942560dec8fdbc3d9b65e31e4b41295a
  Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$1
  minor version: 0
  major version: 52
  flags: ACC_SUPER, ACC_SYNTHETIC
Constant pool:
   #1 = Class              #7             // compiler/SyntheticDemo$1
   #2 = Class              #9             // java/lang/Object
   #3 = Utf8               SourceFile
   #4 = Utf8               SyntheticDemo.java
   #5 = Utf8               EnclosingMethod
   #6 = Class              #10            // compiler/SyntheticDemo
   #7 = Utf8               compiler/SyntheticDemo$1
   #8 = Utf8               InnerClasses
   #9 = Utf8               java/lang/Object
  #10 = Utf8               compiler/SyntheticDemo
{
}
SourceFile: "SyntheticDemo.java"
EnclosingMethod: #6.#0                  // compiler.SyntheticDemo
InnerClasses:
     static #1; //class compiler/SyntheticDemo$1

这个类里面什么都没有,并且此类的flags包含ACC_SYNTHETIC。

SyntheticDemo$InnerClass.class

javap SyntheticDemo$InnerClass.class:

Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$InnerClass {
  compiler.SyntheticDemo$InnerClass(compiler.SyntheticDemo$1);
  static java.lang.String access$100(compiler.SyntheticDemo$InnerClass);
}

javap SyntheticDemo$InnerClass.class:

Classfile /D:/idea_workspace/mycode/target/classes/compiler/SyntheticDemo$InnerClass.class
  Last modified 2019-12-12; size 763 bytes
  MD5 checksum f13a4310236918575d26a2909aa8507e
  Compiled from "SyntheticDemo.java"
class compiler.SyntheticDemo$InnerClass
  minor version: 0
  major version: 52
  flags: ACC_SUPER
Constant pool:
   #1 = Fieldref           #5.#26         // compiler/SyntheticDemo$InnerClass.inner:Ljava/lang/String;
   #2 = Methodref          #5.#27         // compiler/SyntheticDemo$InnerClass."":()V
   #3 = Methodref          #6.#27         // java/lang/Object."":()V
   #4 = String             #28            // 我在内部
   #5 = Class              #30            // compiler/SyntheticDemo$InnerClass
   #6 = Class              #31            // java/lang/Object
   #7 = Utf8               inner
   #8 = Utf8               Ljava/lang/String;
   #9 = Utf8               
  #10 = Utf8               ()V
  #11 = Utf8               Code
  #12 = Utf8               LineNumberTable
  #13 = Utf8               LocalVariableTable
  #14 = Utf8               this
  #15 = Utf8               InnerClass
  #16 = Utf8               InnerClasses
  #17 = Utf8               Lcompiler/SyntheticDemo$InnerClass;
  #18 = Class              #32            // compiler/SyntheticDemo$1
  #19 = Utf8               (Lcompiler/SyntheticDemo$1;)V
  #20 = Utf8               x0
  #21 = Utf8               Lcompiler/SyntheticDemo$1;
  #22 = Utf8               access$100
  #23 = Utf8               (Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
  #24 = Utf8               SourceFile
  #25 = Utf8               SyntheticDemo.java
  #26 = NameAndType        #7:#8          // inner:Ljava/lang/String;
  #27 = NameAndType        #9:#10         // "":()V
  #28 = Utf8               我在内部
  #29 = Class              #33            // compiler/SyntheticDemo
  #30 = Utf8               compiler/SyntheticDemo$InnerClass
  #31 = Utf8               java/lang/Object
  #32 = Utf8               compiler/SyntheticDemo$1
  #33 = Utf8               compiler/SyntheticDemo
{
  compiler.SyntheticDemo$InnerClass(compiler.SyntheticDemo$1);
    descriptor: (Lcompiler/SyntheticDemo$1;)V
    flags: ACC_SYNTHETIC
    Code:
      stack=1, locals=2, args_size=2
         0: aload_0
         1: invokespecial #2                  // Method "":()V
         4: return
      LineNumberTable:
        line 18: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcompiler/SyntheticDemo$InnerClass;
            0       5     1    x0   Lcompiler/SyntheticDemo$1;

  static java.lang.String access$100(compiler.SyntheticDemo$InnerClass);
    descriptor: (Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
    flags: ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: getfield      #1                  // Field inner:Ljava/lang/String;
         4: areturn
      LineNumberTable:
        line 18: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0    x0   Lcompiler/SyntheticDemo$InnerClass;
}
SourceFile: "SyntheticDemo.java"
InnerClasses:
     static #18; //class compiler/SyntheticDemo$1

SyntheticDemo$InnerClass里含有默认访问权限的构造器和access$100方法。并且这个构造器和方法都是synthetic的。构造器的参数是SyntheticDemo$1。access$100的逻辑是获取内部类的私有属性。

SyntheticDemo.class

在看看最后一个class,javap SyntheticDemo.class:

Compiled from "SyntheticDemo.java"
public class compiler.SyntheticDemo {
  public compiler.SyntheticDemo();
  public static void main(java.lang.String[]);
}

javap -v SyntheticDemo.class

Classfile /D:/idea_workspace/mycode/target/classes/compiler/SyntheticDemo.class
  Last modified 2019-12-12; size 1040 bytes
  MD5 checksum 7519ad7d2df356217e19642ed0a06ee4
  Compiled from "SyntheticDemo.java"
public class compiler.SyntheticDemo
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #13.#32        // java/lang/Object."":()V
   #2 = Class              #33            // compiler/SyntheticDemo$InnerClass
   #3 = Methodref          #2.#34         // compiler/SyntheticDemo$InnerClass."":(Lcompiler/SyntheticDemo$1;)V
   #4 = Fieldref           #35.#36        // java/lang/System.out:Ljava/io/PrintStream;
   #5 = Class              #37            // java/lang/StringBuilder
   #6 = Methodref          #5.#32         // java/lang/StringBuilder."":()V
   #7 = String             #38            // inner:
   #8 = Methodref          #5.#39         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #9 = Methodref          #2.#40         // compiler/SyntheticDemo$InnerClass.access$100:(Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
  #10 = Methodref          #5.#41         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #11 = Methodref          #42.#43        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #12 = Class              #44            // compiler/SyntheticDemo
  #13 = Class              #45            // java/lang/Object
  #14 = Class              #46            // compiler/SyntheticDemo$1
  #15 = Utf8               InnerClasses
  #16 = Utf8               InnerClass
  #17 = Utf8               
  #18 = Utf8               ()V
  #19 = Utf8               Code
  #20 = Utf8               LineNumberTable
  #21 = Utf8               LocalVariableTable
  #22 = Utf8               this
  #23 = Utf8               Lcompiler/SyntheticDemo;
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
  #26 = Utf8               args
  #27 = Utf8               [Ljava/lang/String;
  #28 = Utf8               innerObject
  #29 = Utf8               Lcompiler/SyntheticDemo$InnerClass;
  #30 = Utf8               SourceFile
  #31 = Utf8               SyntheticDemo.java
  #32 = NameAndType        #17:#18        // "":()V
  #33 = Utf8               compiler/SyntheticDemo$InnerClass
  #34 = NameAndType        #17:#47        // "":(Lcompiler/SyntheticDemo$1;)V
  #35 = Class              #48            // java/lang/System
  #36 = NameAndType        #49:#50        // out:Ljava/io/PrintStream;
  #37 = Utf8               java/lang/StringBuilder
  #38 = Utf8               inner:
  #39 = NameAndType        #51:#52        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #40 = NameAndType        #53:#54        // access$100:(Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
  #41 = NameAndType        #55:#56        // toString:()Ljava/lang/String;
  #42 = Class              #57            // java/io/PrintStream
  #43 = NameAndType        #58:#59        // println:(Ljava/lang/String;)V
  #44 = Utf8               compiler/SyntheticDemo
  #45 = Utf8               java/lang/Object
  #46 = Utf8               compiler/SyntheticDemo$1
  #47 = Utf8               (Lcompiler/SyntheticDemo$1;)V
  #48 = Utf8               java/lang/System
  #49 = Utf8               out
  #50 = Utf8               Ljava/io/PrintStream;
  #51 = Utf8               append
  #52 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #53 = Utf8               access$100
  #54 = Utf8               (Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
  #55 = Utf8               toString
  #56 = Utf8               ()Ljava/lang/String;
  #57 = Utf8               java/io/PrintStream
  #58 = Utf8               println
  #59 = Utf8               (Ljava/lang/String;)V
{
  public compiler.SyntheticDemo();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcompiler/SyntheticDemo;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #2                  // class compiler/SyntheticDemo$InnerClass
         3: dup
         4: aconst_null
         5: invokespecial #3                  // Method compiler/SyntheticDemo$InnerClass."":(Lcompiler/SyntheticDemo$1;)V
         8: astore_1
         9: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;
        12: new           #5                  // class java/lang/StringBuilder
        15: dup
        16: invokespecial #6                  // Method java/lang/StringBuilder."":()V
        19: ldc           #7                  // String inner:
        21: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        24: aload_1
        25: invokestatic  #9                  // Method compiler/SyntheticDemo$InnerClass.access$100:(Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
        28: invokevirtual #8                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        31: invokevirtual #10                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        34: invokevirtual #11                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        37: return
      LineNumberTable:
        line 14: 0
        line 15: 9
        line 16: 37
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      38     0  args   [Ljava/lang/String;
            9      29     1 innerObject   Lcompiler/SyntheticDemo$InnerClass;
}
SourceFile: "SyntheticDemo.java"
InnerClasses:
     static #14; //class compiler/SyntheticDemo$1

到这里,所有谜题都解开了。在new内部类时,调用了编译器生成的那个构造器,并传递了一个null作为参数:

         5: invokespecial #3                  // Method compiler/SyntheticDemo$InnerClass."":(Lcompiler/SyntheticDemo$1;)V
         8: astore_1

获取内部类的私有属性时,调用的编译生成的access$100方法:

 invokestatic  #9                  // Method compiler/SyntheticDemo$InnerClass.access$100:(Lcompiler/SyntheticDemo$InnerClass;)Ljava/lang/String;
解答

因为内部类是一个私有的,所以默认构造器也会是私有的构造器,那么外部类就无法调用此默认构造器。而我们知道Java语言中外部类是可以构造和访问内部类的,其实现就是编译器耍的花招,编译生成了一些构造器、类、方法,来帮我们把外部类和内部类私有部分连接起来,而这类编译器生成的构造器、方法、类就是synthetic标记的。也就是说这个特性是Java编译器赋予的,而其他运行在JVM上的语言则不一定有此特性,要看其对应的编译器是否也用了一些花招来做连接了。

如果我们给把InnerClass的inner域的private关键字去掉,再查字节码,发现内部类的access$100没有了,因为现在外部类可以直接访问到内部类的包访问权限的域,当然就不需要生成access$100来做桥梁了。读者可以自己试试。
如果我们把InnerClass的内部类private去掉,或者不去掉而是添加一个非private的内部类构造器,那么查看字节码发现,SyntheticDemo$1.class消失了,而且编译器也不生成带SyntheticDemo$1.class参数的包权限构造器了,因为不需要了。读者可以自行试验。

扩展
匿名内部类

匿名内部类用到了synthetic了吗?

public  class SyntheticDemo2 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("11");
            }
        }).start();
    }
}

以上代码也会生成一个SyntheticDemo2$1.class。我们查看其字节码:

Classfile /D:/idea_workspace/mycode/target/classes/compiler/SyntheticDemo2$1.class
  Last modified 2019-12-12; size 503 bytes
  MD5 checksum 207c9ba26f66c2fbfd5d092c7f9f844e
  Compiled from "SyntheticDemo2.java"
final class compiler.SyntheticDemo2$1 implements java.lang.Runnable
  minor version: 0
  major version: 52
  flags: ACC_FINAL, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#19         // java/lang/Object."":()V
   #2 = Class              #20            // compiler/SyntheticDemo2$1
   #3 = Class              #21            // java/lang/Object
   #4 = Class              #22            // java/lang/Runnable
   #5 = Utf8               
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Utf8               LineNumberTable
   #9 = Utf8               LocalVariableTable
  #10 = Utf8               this
  #11 = Utf8               InnerClasses
  #12 = Utf8               Lcompiler/SyntheticDemo2$1;
  #13 = Utf8               run
  #14 = Utf8               SourceFile
  #15 = Utf8               SyntheticDemo2.java
  #16 = Utf8               EnclosingMethod
  #17 = Class              #23            // compiler/SyntheticDemo2
  #18 = NameAndType        #24:#25        // main:([Ljava/lang/String;)V
  #19 = NameAndType        #5:#6          // "":()V
  #20 = Utf8               compiler/SyntheticDemo2$1
  #21 = Utf8               java/lang/Object
  #22 = Utf8               java/lang/Runnable
  #23 = Utf8               compiler/SyntheticDemo2
  #24 = Utf8               main
  #25 = Utf8               ([Ljava/lang/String;)V
{
  compiler.SyntheticDemo2$1();
    descriptor: ()V
    flags:
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 13: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcompiler/SyntheticDemo2$1;

  public void run();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 17: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  this   Lcompiler/SyntheticDemo2$1;
}
SourceFile: "SyntheticDemo2.java"
EnclosingMethod: #17.#18                // compiler.SyntheticDemo2.main
InnerClasses:
     static #2; //class compiler/SyntheticDemo2$1

字节码中没有ACC_SYNTHETIC标记,说明其与 synthetic 无关。

lambda 表达式
class SyntheticDemo3 {

    public static void main(String[] args) {
        new Thread(()->{}).start();
    }

}

只有一个SyntheticDemo3.class
其字节码:

Classfile /D:/idea_workspace/mycode/target/classes/compiler/SyntheticDemo3.class
  Last modified 2019-12-12; size 1042 bytes
  MD5 checksum 50722aaf911c908da83df897f5141c05
  Compiled from "SyntheticDemo3.java"
class compiler.SyntheticDemo3
  minor version: 0
  major version: 52
  flags: ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#22         // java/lang/Object."":()V
   #2 = Class              #23            // java/lang/Thread
   #3 = InvokeDynamic      #0:#28         // #0:run:()Ljava/lang/Runnable;
   #4 = Methodref          #2.#29         // java/lang/Thread."":(Ljava/lang/Runnable;)V
   #5 = Methodref          #2.#30         // java/lang/Thread.start:()V
   #6 = Class              #31            // compiler/SyntheticDemo3
   #7 = Class              #32            // java/lang/Object
   #8 = Utf8               
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Lcompiler/SyntheticDemo3;
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               args
  #18 = Utf8               [Ljava/lang/String;
  #19 = Utf8               lambda$main$0
  #20 = Utf8               SourceFile
  #21 = Utf8               SyntheticDemo3.java
  #22 = NameAndType        #8:#9          // "":()V
  #23 = Utf8               java/lang/Thread
  #24 = Utf8               BootstrapMethods
  #25 = MethodHandle       #6:#33         // invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke
/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #26 = MethodType         #9             //  ()V
  #27 = MethodHandle       #6:#34         // invokestatic compiler/SyntheticDemo3.lambda$main$0:()V
  #28 = NameAndType        #35:#36        // run:()Ljava/lang/Runnable;
  #29 = NameAndType        #8:#37         // "":(Ljava/lang/Runnable;)V
  #30 = NameAndType        #38:#9         // start:()V
  #31 = Utf8               compiler/SyntheticDemo3
  #32 = Utf8               java/lang/Object
  #33 = Methodref          #39.#40        // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;L
java/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #34 = Methodref          #6.#41         // compiler/SyntheticDemo3.lambda$main$0:()V
  #35 = Utf8               run
  #36 = Utf8               ()Ljava/lang/Runnable;
  #37 = Utf8               (Ljava/lang/Runnable;)V
  #38 = Utf8               start
  #39 = Class              #42            // java/lang/invoke/LambdaMetafactory
  #40 = NameAndType        #43:#47        // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/l
ang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #41 = NameAndType        #19:#9         // lambda$main$0:()V
  #42 = Utf8               java/lang/invoke/LambdaMetafactory
  #43 = Utf8               metafactory
  #44 = Class              #49            // java/lang/invoke/MethodHandles$Lookup
  #45 = Utf8               Lookup
  #46 = Utf8               InnerClasses
  #47 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/
lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
  #48 = Class              #50            // java/lang/invoke/MethodHandles
  #49 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #50 = Utf8               java/lang/invoke/MethodHandles
{
  compiler.SyntheticDemo3();
    descriptor: ()V
    flags:
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."":()V
         4: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcompiler/SyntheticDemo3;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=1, args_size=1
         0: new           #2                  // class java/lang/Thread
         3: dup
         4: invokedynamic #3,  0              // InvokeDynamic #0:run:()Ljava/lang/Runnable;
         9: invokespecial #4                  // Method java/lang/Thread."":(Ljava/lang/Runnable;)V
        12: invokevirtual #5                  // Method java/lang/Thread.start:()V
        15: return
      LineNumberTable:
        line 11: 0
        line 12: 15
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  args   [Ljava/lang/String;
}
SourceFile: "SyntheticDemo3.java"
InnerClasses:
     public static final #45= #44 of #48; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
  0: #25 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/Method
Type;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #26 ()V
      #27 invokestatic compiler/SyntheticDemo3.lambda$main$0:()V
      #26 ()V

lambda表达式没有通过内部类实现,而是通过invokedynamic这个指令解决的。有机会写一遍invokedynamic的文章。

更多Java文章,请关注公众号:
公众号.png

你可能感兴趣的:(java,编译器)