Now I can understand that compiler why emit o.getClass() to checking whether the reference is null,since compiler make sure enclosing class instance is not null before pass it into inner class constructor then inner class can refer enclosing class instance by EnclosingClass.this
when create inner class / lambda expression instance.
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???
};
}
Thanks to @Holger give me more feedback & references, After dump byte code by using javap -v -p -c com.holi.functions.EnclosingClass
command, I found invokedynamic
instruction before put a field of Supplier via 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;
and invokedynamic
instruction invoked with a BootstrapMethod 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;
the BootstrapMethods 0
refered a function implemetation method lambda$new$0
in EnclosingClass that generated by compiler.
private com.holi.functions.EnclosingClass lambda$new$0();
Code:
0: aload_0
1: areturn
Question
A synthetic lambda expression inner class created by JVM in memory (it is an inner class but not generated with class file so I think it is generated in memory) via MethodHandle.invoke.
@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
doing something in constructor like this:
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);
}
So this
in lambda expression is an instance of EnclosingClass, since the lambda expression implementation method defined on EnclosingClass. and the lambda expression inner class is adapter class to adaptee implementation method of EnclosingClass(lambda$new$0
) to FunctionInterface(Supplier
). What I said above right? Please give me more references link if I'm right/wrong,thanks everybody.