!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中没有为这种类型指定格式是遗漏的。
后果
上面仅描述和解释了现状,表明没有任何规范告诉编译器的行为与当前状态有所不同。显然,这不是完全理想的情况。
- 可能有人希望与Oracle联系,并提到Java 8引入了JVMS部分未涵盖的情况。一旦局部变量也受类型推断的影响,这种情况可能变得更加相关。
- 希望看到当前情况的负面影响的任何人都可以通过494198(ecj)报名参加,否则优先级较低。
更新:
同时,有人报告了一个示例,其中需要常规的
Signature
属性(不能机会性地省略)来编码无法根据JVMS进行编码的类型。在这种情况下,javac也会创建未指定的字节码。根据后续文章, 任何变量 都不应该
具有这样的类型,但我认为讨论尚未结束(顺便说一句,JLS尚未确保这一目标)。
更新2: 在收到规范作者的建议后,我看到了最终解决方案的三个部分:
(1)任何字节码属性中的每个类型签名都 必须 遵守JVMS 4.7.9.1中的语法。ecj
!和javac 都不
<capturedwildcard>合法。
(2)编译器 应 在不存在合法编码的 情况下 近似类型签名,例如,使用擦除而不是捕获。对于LVTT条目,这种近似应视为合法。
(3)JLS 必须 确保只有使用JVMS 4.7.9.1可编码的类型才会出现在必须生成Signature属性的位置。
对于ecj的将来版本,已解决(1)和(2)。我不能谈论javac和JLS何时进行相应修复的时间表。



