您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

Lambda的行为与匿名内部类不同

Lambda的行为与匿名内部类不同

根据生成的字节码:

Java(TM)SE运行时环境(内部版本1.8.0-b132)

 private static java.lang.Integer lambda$main$0(java.lang.Integer);
   descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
   flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
   Code:
     stack=2, locals=2, args_size=1
        0: aload_0
        1: invokevirtual #9                  // Method java/lang/Integer.intValue:()I
        4: iconst_1
        5: iadd
        6: invokestatic  #6                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        9: dup
       10: astore_0
       11: astore_1
       12: aload_0
       13: areturn
     LineNumberTable:
       line 20: 0
     LocalVariableTable:
       Start  Length  Slot  Name   Signature
           0      14     0     t   Ljava/lang/Integer;

  public java.lang.Integer get(java.lang.Integer);
    descriptor: (Ljava/lang/Integer;)Ljava/lang/Integer;
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=2
         0: aload_1
         1: astore_2
         2: aload_1
         3: invokevirtual #2                  // Method java/lang/Integer.intValue:()I
         6: iconst_1
         7: iadd
         8: invokestatic  #3                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        11: dup
        12: astore_1
        13: astore_3
        14: aload_2
        15: areturn
      LineNumberTable:
        line 16: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      16     0  this   LTest$1;
            0      16     1     t   Ljava/lang/Integer;

如您所见,在匿名类中,从本地变量表(方法参数 )加载变量后,运行时将参数的副本存储在另一个变量( )中,然后使用该参数副本作为返回值。

Lambda方法不会复制参数(加载->取消装箱->添加1->框->存储->加载->返回)。

绝对是javac错误

我来自http://hg.openjdk.java.net/jdk8u/jdk8u

匿名类和lambda转换为以下中间表示形式:

@Override()
public Integer get(Integer t) {
    return (let /*synthetic*/ final Integer $112619572 = t in 
       (let /*synthetic*/ final Integer $1295226194 = t = Integer.valueOf((int)(t.intValue() + 1)) in $112619572));
}

/*synthetic*/ private static Integer lambda$main$0(final Integer t) {
    return (let /*synthetic*/ final Integer $1146147158 = t = Integer.valueOf((int)(t.intValue() + 1)) in t);
}

在lambda中,生成方法参数标记为final,因为LambdaToMethod转换器将所有参数标记为FINAL(根据源代码 )。

然后让表达式生成器检查变量标志,以及是否在最终变量时忽略临时变量生成(根据源代码 ),因为认为禁止进行修改

可能的解决方案:

从lamda生成方法中的局部变量( )和参数( )中删除FINAL标志:

 case LOCAL_VAR:

ret = new VarSymbol(FINAL, name, types.erasure(sym.type), translatedSym); …

case PARAM: ret = new VarSymbol(FINAL | PARAMETER, name, types.erasure(sym.type), translatedSym); …

删除了FINAL标志,并从以下网址获得了预期的测试结果:https ://bugs.openjdk.java.net/browse/JDK-8038420

其他 2022/1/1 18:30:50 有239人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶