lambda表达式`this`如何引用封闭类

时间:2017-03-30 16:22:46

标签: java java-8

现在我可以理解编译器为什么发出o.getClass()来检查引用是否为null,因为编译器确保在将类实例传递给内部类构造函数之前封闭类实例不为null,然后内部类可以引用封闭类实例创建内部类/ lambda表达式实例时EnclosingClass.this

class EnclosingClass {
    class InnerClass {
        public Object reference() {
            return this;//this refer to InnerClass instance
        }
    }

    Supplier<Object> reference = () -> {
        return this;//why this refer to EnclosingClass instance???
    };
}

感谢@Holger给我更多反馈&amp;引用,在使用javap -v -p -c com.holi.functions.EnclosingClass命令转储字节代码后,在通过invokedynamic放置供应商字段之前,我找到了putfield指令。

 4: aload_0
 5: aload_0
 6: invokedynamic #2,  0              // InvokeDynamic #0:get:(Lcom/holi/functions/EnclosingClass;)Ljava/util/function/Supplier;
11: putfield      #3                  // Field reference:Ljava/util/function/Supplier;
使用BootstrapMethod invokedynamic调用

0指令:

BootstrapMethods:
  0: #26 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:
      #27 ()Ljava/lang/Object;
      #28 invokespecial com/holi/functions/EnclosingClass.lambda$new$0:()Lcom/holi/functions/EnclosingClass;
      #29 ()Lcom/holi/functions/EnclosingClass;

BootstrapMethods 0引用了由编译器生成的EnclosingClass中的函数实现方法lambda$new$0

private com.holi.functions.EnclosingClass lambda$new$0();
Code:
     0: aload_0
     1: areturn

问题

由JVM在内存中创建的合成lambda表达式内部类(它是一个内部类,但不是通过类文件生成所以我认为它是在内存中生成的)来自MethodHandle.invoke。 / p>

@Test
void lambdaClassCreatedAConstructorWithAParameterOfLambdaContextClass() throws Throwable {
    Object[] parameterTypes = Arrays.stream(lambdaClass.getDeclaredConstructors())
            .map(Constructor::getParameterTypes).toArray(Object[]::new);

    assertThat(parameterTypes, equalTo(new Object[][]{{lambdaContextClass}}));
}

@Test
void lambdaClassCreatedAnInstanceFieldOfLambdaContextClass() throws Throwable {
    Object[] fieldTypes = Arrays.stream(lambdaClass.getDeclaredFields())
            .map(Field::getType).toArray(Object[]::new);

    assertThat(fieldTypes, equalTo(new Object[]{lambdaContextClass}));
}

invokedynamic在构造函数中执行此操作:

private Supplier<EnclosingClassLambdaExpressionTest> invokeDynamic() throws Throwable {
    MethodHandles.Lookup caller = MethodHandles.lookup();
    MethodType instantiatedMethodType = methodType(lambdaContextClass);
    // InvokeDynamic #0:get:(Lcom/holi/functions/EnclosingClass;)Ljava/util/function/Supplier;
    // BootstrapMethods:
    //   0: #23 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:
    //       #24 ()Ljava/lang/Object;
    //       #25 invokespecial com/holi/functions/EnclosingClass.lambda$new$0:()Lcom/holi/functions/EnclosingClass;
    //       #26 ()Lcom/holi/functions/EnclosingClass;
    CallSite site = LambdaMetafactory.metafactory(caller,
            "get"
            , methodType(Supplier.class, lambdaContextClass)
            , methodType(Object.class)
            , caller.findVirtual(lambdaContextClass, "lambda$new$0", instantiatedMethodType)
            , instantiatedMethodType
    );
    return (Supplier<EnclosingClassLambdaExpressionTest>) site.dynamicInvoker().invokeExact(lambdaContext);
}

因此,lambda表达式中的this是EnclosingClass的一个实例,因为在EnclosingClass上定义了lambda表达式实现方法。 lambda表达式内部类是适配器类,用于将EnclosingClass(lambda$new$0)的实现方法适配到FunctionInterface(Supplier)。我上面说的对吗?如果我对/错,请给我更多参考链接,谢谢大家。

0 个答案:

没有答案
相关问题