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

public static CallSite metafactory(MethodHandles.Lookup caller,
                                      String invokedName,
                                      MethodType invokedType,
                                      MethodType samMethodType,
                                      MethodHandle implMethod,
                                      MethodType instantiatedMethodType)
            throws LambdaConversionException {
        AbstractValidatingLambdaMetafactory mf;
        mf = new InnerClassLambdaMetafactory(caller, invokedType,
                                            invokedName, samMethodType,
                                            implMethod, instantiatedMethodType,
                                            false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY);
        mf.validateMetafactoryArgs();
        return mf.buildCallSite();
    }

在buildCallSite的函数中

CallSite buildCallSite() throws LambdaConversionException {
        final Class<?> innerClass = spinInnerClass();

函数spinInnerClass 构建了这个内部类,也就是生成了一个Lambda$$Lambda$1/716157500 这样的内部类,这个类是在运行的时候构建的,并不会保存在磁盘中,如果想看到这个构建的类,可以通过设置环境参数

System.setProperty("jdk.internal.lambda.dumpProxyClasses", ".");

会在你指定的路径 . 当前运行路径上生成这个内部类

3.静态类

Java在编译表达式的时候会生成lambda$0静态私有类,在这个类里实现了表达式中的方法块 system.out.println(s);

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;

当然了在上一步通过设置的jdk.internal.lambda.dumpProxyClasses里生成的Lambda$$Lambda$1.class

public void accept(java.lang.Object);
    descriptor: (Ljava/lang/Object;)V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=2
        0: aload_1
        1: checkcast    #15                // class java/lang/String
        4: invokestatic  #21                // Method Lambda.lambda$0:(Ljava/lang/String;)V
        7: return
    RuntimeVisibleAnnotations:
      0: #13()

调用了Lambda.lambda$0静态函数,也就是表达式中的函数块

总结

这样就完成的实现了Lambda表达式,使用invokedynamic指令,运行时调用LambdaMetafactory.metafactory动态的生成内部类,实现了接口,内部类里的调用方法块并不是动态生成的,只是在原class里已经编译生成了一个静态的方法,内部类只需要调用该静态方法。

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

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