简体   繁体   English

具有非静态上下文的 Invokedynamic

[英]Invokedynamic with non-static context

I learnt that invokedynamic instruction of bytecode calls a static method representation of lambda.我了解到, invokedynamic字节码指令调用static拉姆达的方法表示。

Please let me know if that is incorrect.如果这不正确,请告诉我。

if correct, then how is below code working?如果正确,那么下面的代码如何工作?

String[] arr = new String[1];
Stream.of(arr).forEach((s) -> System.out.println(this));

It's not correct to say that lambda expressions were always compiled to a static method.说 lambda 表达式总是被编译为static方法是不正确的。 It's not specified, how they are compiled, which leaves room for two different strategies for a lambda expression that captures this , like your s -> System.out.println(this) .没有指定它们是如何编译的,这为捕获this的 lambda 表达式的两种不同策略留下了空间,例如您的s -> System.out.println(this)

  1. use an instance method:使用实例方法:

     private void compiler$chosen$name(String s) { System.out.println(this); }
  2. use a static method:使用static方法:

     private static void compiler$chosen$name(TypeOfThis var0, String s) { System.out.println(var0); }

Both methods work equally well when the invokedynamic instruction points to a bootstrap method in the LambdaMetafactory .invokedynamic指令指向LambdaMetafactory的引导方法时,这两种方法同样有效。 In either case, the invokedynamic instruction will have a signature consuming a TypeOfThis instance and producing a Consumer<String> .在任何一种情况下, invokedynamic指令都会有一个签名,使用TypeOfThis实例并生成一个Consumer<String> From the documentation of the LambdaMetafactory , you can derive that it will treat the receiver of a non- static target method like an implied the first argument, which makes the functional signature of both variants identical.LambdaMetafactory的文档中,您可以得出它会将非static目标方法的接收者视为隐含的第一个参数,这使得两个变体的功能签名相同。 All that matters, is that the argument to the consumer's accept method has to correspond to the last argument of the list.重要的是消费者的accept方法的参数必须对应于列表的最后一个参数。

I've encountered both strategies in practice, so this is indeed compiler dependent.我在实践中遇到过这两种策略,所以这确实依赖于编译器。

Note that these strategies also work on source code level, when using method references:请注意,当使用方法引用时,这些策略也适用于源代码级别:

public class Example {
    BiConsumer<Example,String> variant1 = Example::instanceMethod;
    BiConsumer<Example,String> variant2 = Example::staticMethod;

    private void instanceMethod(String s) {
        System.out.println(this);
    }

    private static void staticMethod(Example instance, String s) {
        System.out.println(instance);
    }
}

This demonstrates the equivalence of a method receiver and the the first argument to a static method.这演示了方法接收器和static方法的第一个参数的等效性。 However, when it comes to binding an argument, only Consumer<String> c = this::instanceMethod;但是,当涉及到绑定参数时,只有Consumer<String> c = this::instanceMethod; works with method references.使用方法引用。 The other binding features of the LambdaMetafactory are only used by compiler generated code for lambda expressions. LambdaMetafactory的其他绑定功能仅由编译器生成的 lambda 表达式代码使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM