How does the lambda expression `this` refer to an instance of the enclosing class

Now I can understand that the compiler why emit o.getClass () is checking if the reference is null, since the compiler will make sure the inclusion of the class instance is not null before passing it in the inner class constructor, then the inner class can refer to the instance instance class on EnclosingClass.this

when instantiating the inner class / lambda.

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 and links. After dump bytecode using the command, javap -v -p -c com.holi.functions.EnclosingClass

I found the instruction invokedynamic

before putting the Provider via field 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

, called using the BootstrapMethod method 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

refers to the lambda$new$0

compiler-generated method to implement a function in EnclosingClass.

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

      

Question

Inner synthetic lambda expression class generated by the JVM in memory (this is an inner class, but not generated by the 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

do something in the constructor:

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 the expression, the lambda is an instance of EnclosingClass because the implementation method of the lambda expression is defined on EnclosingClass. and the inner lambda expression class is an adapter class for adapting the EnclosingClass ( lambda$new$0

) implementation method to FunctionInterface ( Supplier

). What did I say above? Please give me a link to other links if I'm right / wrong, thanks everyone.

+3


source to share





All Articles