现在我可以理解编译器为什么发出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
)。我上面说的对吗?如果我对/错,请给我更多参考链接,谢谢大家。