让我们使用 Eclipse Mars.2 包中的 ECJ 编译器编译以下代码:
import java.util.stream.*;
public class Test {
String test(Stream<?> s) {
return s.collect(Collector.of(() -> "", (a, t) -> {}, (a1, a2) -> a1));
}
}
编译命令如下:
$ java -jar org.eclipse.jdt.core_3.11.2.v20160128-0629.jar -8 -g Test.java
编译成功后,让我们检查生成的类文件javap -v -p Test.class
。最有趣的是为(a, t) -> {}
lambda 生成的合成方法:
private static void lambda$1(java.lang.String, java.lang.Object);
descriptor: (Ljava/lang/String;Ljava/lang/Object;)V
flags: ACC_PRIVATE, ACC_STATIC, ACC_SYNTHETIC
Code:
stack=0, locals=2, args_size=2
0: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 a Ljava/lang/String;
0 1 1 t Ljava/lang/Object;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 1 1 t !*
!*
看到这个条目我很惊讶LocalVariableTypeTable
。JVM 规范涵盖LocalVariableTypeTable 属性并说:
该
constant_pool
索引处的条目必须包含一个CONSTANT_Utf8_info
结构(第 4.4.7 节),该结构表示一个字段签名,该签名对源程序中的局部变量的类型进行编码(第 4.7.9.1 节)。
§4.7.9.1定义了字段签名的语法,如果我理解正确,它不涵盖任何类似于!*
.
还应该注意的是,javac 编译器和较早的 ECJ 3.10.x 版本都不会生成此条LocalVariableTypeTable
目。是!*
一些非标准的 Eclipse 扩展还是我在 JVM 规范中遗漏了一些东西?这是否意味着 ECJ 不符合 JVM 规范?实际上是什么!*
意思,是否有任何其他类似的字符串可能出现在LocalVariableTypeTable
属性中?