20

我一直在阅读 Java 语言规范,第 3 版,并发现我认为规范和 javac 编译器实现之间存在差异。Eclipse 编译器中也存在相同的差异。

15.16节讨论了强制转换表达式。它说如果参数类型无法通过强制转换转换为强制类型转换(第 5.5 节),则应该是编译时错误:

如果操作数的编译时类型可能永远不会根据强制转换规则(第 5.5 节)强制转换为强制转换运算符指定的类型,则这是一个编译时错误。否则,在运行时,操作数的值会通过强制转换为强制转换运算符指定的类型进行转换(如有必要)。

5.5节讨论了强制转换。它给出了允许的转换类型列表。列表中特别缺少的是“拆箱转换,然后是扩大/缩小原始转换”。然而,javac 编译器(以及 Eclipse 编译器)似乎确实允许这种确切的转换顺序。例如:

long l = (long) Integer.valueOf(45);

...编译得很好。(有问题的转换是转换为long; 参数是 type java.lang.Integer,因此转换需要取消装箱,int然后是扩大的原始转换)。

同样,根据 JLS,应该不可能转换 from byteto char,因为(根据5.1.4)需要扩大原始转换缩小原始转换 - 但是,编译器也允许这种转换。

任何人都可以启发我吗?

编辑:因为问这个,我已经向 Oracle 提交了一个错误报告。他们的回应是,这是“JLS 中的一个小故障”。

4

2 回答 2

3

我认为您是对的,编译器是对的,而规范是错误的....

这会编译:(Object)45这不会:(Long)45

理解编译器行为(包括我正在使用的 Intellij)的唯一方法是修改 Casting Conversion 以与 Assignment Conversion 和 Method Invocation Conversion 一致:

  • 一个装箱转换(第 5.1.7 节)可选地后跟扩大参考转换

  • 一个拆箱转换(第 5.1.8 节)可选地后跟一个扩大的原始转换。

  • 扩大和缩小原始对流

规范确实说“强制转换比赋值或方法调用转换更具包容性:强制转换可以进行除字符串转换或捕获转换之外的任何允许的转换”

于 2011-03-22T02:45:00.700 回答
1

根据我的阅读,这个子句允许从intto 转换:long

一个原始类型的值可以通过恒等转换(如果类型相同)或通过扩大原始类型转换或缩小原始类型转换为另一种原始类型。

转换intlong是一种扩大的原始转换

剩下的只是从Integerto的转换int,最后一个项目符号包含了这个转换:

拆箱转换

当然,long在示例中甚至不需要强制转换为。

考虑以下四个定义:

final Integer io = Integer.valueOf(45);
final int i = io;
final long l1 = (long)i;
final long l2 = i;

你认为其中任何一个令人惊讶吗?您的原始示例看起来没有任何不同;它只是省略了中间变量。

于 2011-03-22T02:28:43.713 回答