让我们使用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
属性中可能还会出现其他类似的字符串吗?
!
ecj使用该令牌在通用签名中对捕获类型进行编码。因此!*
表示捕获了无限制的通配符。
在内部,ecj使用的两种风格CaptureBinding
,一种实现JLS
18.4
称为“新鲜类型变量”,另一种实现捕获la
JLS
5.1.10(使用与“自由类型变量”相同的术语)。两者都使用产生签名!
。仔细观察,在此示例中,我们有一个“旧式”捕获:t
具有type
capture#1-of ?
,捕获<T>
in Stream<T>
。
问题是:JVMS
4.7.9.1。似乎没有为这种新鲜的类型变量定义编码(其他属性在源代码中没有对应关系,因此也没有名称)。
我无法为lambda javac
发出任何信号LocalVariableTypeTable
,因此它们可能只是避免回答这个问题。
鉴于两个编译器都同意推断t
捕获,为什么一个编译器生成LVTT,而另一个则不生成?JVMS
4.7.14拥有这个
这种差异仅对类型使用类型变量或参数化类型的变量有意义。
根据JLS,捕获是新鲜的类型变量,因此LVTT条目很重要,并且在JVMS中没有为这种类型指定格式是遗漏的。
上面仅描述和解释了现状,表明没有任何规范告诉编译器的行为与当前状态有所不同。显然,这不是完全理想的情况。
更新:
同时,有人报告了一个示例,其中需要常规的
Signature
属性(不能机会性地省略)来编码无法根据JVMS进行编码的类型。在这种情况下,javac也会创建未指定的字节码。根据后续文章, 任何变量 都不应该
具有这样的类型,但我认为讨论尚未结束(顺便说一句,JLS尚未确保这一目标)。
更新2: 在收到规范作者的建议后,我看到了最终解决方案的三个部分:
(1)任何字节码属性中的每个类型签名都 必须 遵守JVMS 4.7.9.1中的语法。ecj !
和javac 都不<captured wildcard>
合法。
(2)编译器 应 在不存在合法编码的 情况下 近似类型签名,例如,使用擦除而不是捕获。对于LVTT条目,这种近似应视为合法。
(3)JLS 必须 确保只有使用JVMS 4.7.9.1可编码的类型才会出现在必须生成Signature属性的位置。
对于ecj的将来版本,已解决(1)和(2)。我不能谈论javac和JLS何时进行相应修复的时间表。
由于IntelliJ,我发现需要将以下选项传递给:
我试图使用Boost的program_options库来构建一个简单的命令行应用程序库,但它失败了,出现了一个非常奇怪的错误。以下是所有有问题的代码(是的,非常简单): 发生的编译错误是: 错误C2679:二进制' 错误C2228:左边的'。“失败”必须具有类/struct/union c:\work\digitalbp\projects\releasedev\nsdk\u 4\u 0\dev\s
问题内容: 我有一个在j2me项目和android项目中引用的java项目。在这个项目中,我想使用条件编译。 就像是… 我一直在阅读有关此内容的信息,但没有发现任何有用的信息。 问题答案: 您可以使用Antenna(有一个Eclipse插件,您可以将其与Ant构建系统一起使用)。我正在按照您描述的方式在我的项目中使用它,并且效果很好:) 编辑:这是与@ WhiteFang34解决方案相关的示例,是
问题内容: 在Eclipse中运行Ant构建时,出现以下错误消息,并且Ant构建失败。 错误消息: 运行javac.exe编译器时出错 停止构建的行: 有人遇到过类似的问题吗?还是有人知道这是怎么回事? 系统信息:Eclipse Helio,JDK 1.5 问题答案: 我有同样的问题,问题是,在Eclipse中,java.home是指JRE而不是JDK。我进行了更改,构建成功。您可以执行以下操作将
当我从Eclipse构建到maven构建时,我发现了项目中的许多问题。我使用2.5.1编译器插件。 JDK是开放的-JDK-7 我在一个新项目中隔离了这个问题,并对其进行了深入研究。问题是: 这无法使用javaC进行编译(但在Eclipse中工作),并说明以下错误: [错误]无法执行目标组织。阿帕奇。专家插件:maven编译器插件:2.5.1:项目测试时编译(默认编译):编译失败 [错误]/hom