Java 8 动态类型语言Lambda表达式实现原理分析

Java 8支持动态语言,看到了很酷的Lambda表达式,对一直以静态类型语言自居的Java,让人看到了Java虚拟机可以支持动态语言的目标。

import java.util.function.Consumer;

public class Lambda {
 public static void main(String[] args) {
  Consumer<String> c = s -> System.out.println(s);
  c.accept("hello lambda!");
 }
}

刚看到这个表达式,感觉java的处理方式是属于内部匿名类的方式

public class Lambda {
 static {
  System.setProperty("jdk.internal.lambda.dumpProxyClasses", ".");
 }
 public static void main(String[] args) {
  Consumer<String> c = new Consumer<String>(){
   @Override
   public void accept(String s) {
    System.out.println(s);
   }
   };
  c.accept("hello lambda");
 }
}

编译的结果应该是Lambda.class , Lambda$1.class 猜测在支持动态语言java换汤不换药,在最后编译的时候生成我们常见的方式。

但是结果不是这样的,只是产生了一个Lambda.class

反编译吧,来看看真相是什么?

javap -v -p Lambda.class

注意  -p 这个参数 -p 参数会显示所有的方法,而不带默认是不会反编译private 的方法的

public Lambda();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
        0: aload_0
        1: invokespecial #21                // Method java/lang/Object."<init>":()V
        4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name  Signature
            0      5    0  this  LLambda;

public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
        0: invokedynamic #30,  0            // InvokeDynamic #0:accept:()Ljava/util/function/Consumer;
        5: astore_1
        6: aload_1
        7: ldc          #31                // String hello lambda
        9: invokeinterface #33,  2          // InterfaceMethod java/util/function/Consumer.accept:(Ljava/lang/Object;)V
        14: return
      LineNumberTable:
        line 8: 0
        line 9: 6
        line 10: 14
      LocalVariableTable:
        Start  Length  Slot  Name  Signature
            0      15    0  args  [Ljava/lang/String;
            6      9    1    c  Ljava/util/function/Consumer;
      LocalVariableTypeTable:
        Start  Length  Slot  Name  Signature
            6      9    1    c  Ljava/util/function/Consumer<Ljava/lang/String;>;

private static void lambda$0(java.lang.String);
    descriptor: (Ljava/lang/String;)V
    flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=2, locals=1, args_size=1
        0: getstatic    #46                // Field java/lang/System.out:Ljava/io/PrintStream;
        3: aload_0
        4: invokevirtual #50                // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        7: return
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name  Signature
            0      8    0    s  Ljava/lang/String;
}
SourceFile: "Lambda.java"
BootstrapMethods:
  0: #66 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;
    Method arguments:
      #67 (Ljava/lang/Object;)V
      #70 invokestatic Lambda.lambda$0:(Ljava/lang/String;)V
      #71 (Ljava/lang/String;)V
InnerClasses:
    public static final #77= #73 of #75; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles

在这里我们发现了几个与我们常见的java不太一样的地方,由于常量定义太多了,文章中就不贴出了

1. Invokedynamic 指令

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/2242e03a704b722bde26da8ed4a5384f.html