首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Java 8中有效的最终和最终

在Java 8中有效的最终和最终
EN

Stack Overflow用户
提问于 2021-12-17 16:40:16
回答 1查看 328关注 0票数 13

我正在执行以下主要方法:

代码语言:javascript
复制
int secrete = 42;
for (int i = 0; i < 5; i++) {
    Consumer<String> myprinter2 =
                    msg -> {
                        System.out.println("consuming " + msg + " ," + secrete);
                    };
     myprinter2.accept(myprinter2.toString());
}

上述代码的输出是:

代码语言:javascript
复制
consuming Main$$Lambda$1/1324119927@6d311334 ,42
consuming Main$$Lambda$1/1324119927@682a0b20 ,42
consuming Main$$Lambda$1/1324119927@3d075dc0 ,42
consuming Main$$Lambda$1/1324119927@214c265e ,42
consuming Main$$Lambda$1/1324119927@448139f0 ,42

如果我将secrete更改为最终结果,则输出如下:

代码语言:javascript
复制
consuming Main$$Lambda$1/2003749087@41629346 ,42
consuming Main$$Lambda$1/2003749087@41629346 ,42
consuming Main$$Lambda$1/2003749087@41629346 ,42
consuming Main$$Lambda$1/2003749087@41629346 ,42
consuming Main$$Lambda$1/2003749087@41629346 ,42

secrete实际上是最终的,即使我没有声明它是最终的,那么为什么每个lambda都被认为是一个新的对象,而我没有声明它是最终的呢?

EN

回答 1

Stack Overflow用户

发布于 2021-12-17 18:25:41

“有效的最终”在技术上并不是必需的,如果没有它,它是可以做到的。但是语言设计人员为了避免混淆而设置了这个限制,因为如果变量不断变化,lambda会看到什么值,初始值还是最新值?其他有lambda的语言没有这个限制,规范设置了对这个用例的期望。

考虑到以下代码:

代码语言:javascript
复制
import java.util.function.Consumer;


class Main {  
  public static void main(String args[]) { 
    int i = 42;
    final int j = 41;
    for (int k = 0; k < 5; k++) {
      Consumer<String> x = msg -> System.out.printf("x=%s, i=%d%n", msg, i);
      Consumer<String> y = msg -> System.out.printf("y=%s, j=%d%n", msg, j);
      Consumer<String> z = msg -> System.out.printf("z=%s%n", msg);
      x.accept(x.toString());
      y.accept(y.toString());
      z.accept(z.toString());
    }
  } 
}

当我们使用javap -c -v Main.class检查生成的字节码时,我们看到:

代码语言:javascript
复制
11: invokedynamic #7,  0              // InvokeDynamic #0:accept:(I)Ljava/util/function/Consumer;
16: astore_3
17: invokedynamic #11,  0             // InvokeDynamic #1:accept:()Ljava/util/function/Consumer;
22: astore        4
24: invokedynamic #14,  0             // InvokeDynamic #2:accept:()Ljava/util/function/Consumer;

我们可以看到兰巴达是如何翻译的。相应的static方法表明,第一个lambda是一个捕获lambda,在转换后有一个整数第1参数(#71),而其他的没有。

代码语言:javascript
复制
BootstrapMethods:
  0: #63 REF_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:
      #70 (Ljava/lang/Object;)V
      #71 REF_invokeStatic Main.lambda$main$0:(ILjava/lang/String;)V
      #74 (Ljava/lang/String;)V
  1: #63 REF_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:
      #70 (Ljava/lang/Object;)V
      #75 REF_invokeStatic Main.lambda$main$1:(Ljava/lang/String;)V
      #74 (Ljava/lang/String;)V
  2: #63 REF_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:
      #70 (Ljava/lang/Object;)V
      #78 REF_invokeStatic Main.lambda$main$2:(Ljava/lang/String;)V
      #74 (Ljava/lang/String;)V

所以,这就是兰巴达的翻译方式。您可以在这篇文章中找到更多细节。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70396304

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档