Java 转换:是编译器错了,还是语言规范错了,还是我错了? [英] Java casting: is the compiler wrong, or is the language spec wrong, or am I wrong?
问题描述
我一直在阅读 Java 语言规范第 3 版,并发现我认为规范与 javac 编译器实现之间存在差异.Eclipse 编译器中也存在同样的差异.
I have been reading the Java Language Spec, 3rd edition, and have found what I think is a discrepancy between the spec and the javac compiler implementation. The same discrepancies exist in the Eclipse compiler.
第 15.16 部分讨论了强制转换表达式.它说,如果参数类型不能通过强制转换(第 5.5 节)转换为强制类型,则应该是编译时错误:
Section 15.16 talks about cast expressions. It says that it should be a compile time error if the argument type cannot be converted to the cast type via casting conversion (section 5.5):
如果根据转换转换规则(第 5.5 节),操作数的编译时类型可能永远不会转换为转换运算符指定的类型,那么这是一个编译时错误.否则,在运行时,通过将转换转换为转换运算符指定的类型来转换操作数值(如有必要).
It is a compile-time error if the compile-time type of the operand may never be cast to the type specified by the cast operator according to the rules of casting conversion (§5.5). Otherwise, at run-time, the operand value is converted (if necessary) by casting conversion to the type specified by the cast operator.
第 5.5 部分讨论了强制转换.它给出了允许的转换类型列表.列表中特别缺少的是拆箱转换后加宽/缩小原始转换".但是 javac 编译器(以及 Eclipse 编译器)似乎确实允许这种确切的转换顺序.例如:
Section 5.5 talks about casting conversion. It gives a list of conversion types which are allowed. Specifically absent from the list is "unboxing conversion followed by widening/narrowing primitive conversion". However that exact sequence of conversions does seem to be allowed by the javac compiler (and also the Eclipse compiler). For instance:
long l = (long) Integer.valueOf(45);
... 编译得很好.(有问题的转换是转换为 long
;参数的类型为 java.lang.Integer
,因此转换需要拆箱到 int
通过扩大原始转换).
... compiles just fine. (The problematic cast is the cast to long
; the argument is of type java.lang.Integer
, so the conversion requires unboxing to int
followed by a widening primitive conversion).
同样,根据 JLS 不应该将 byte
转换为 char
,因为那样(根据 5.1.4) 需要扩大原始转换和缩小原始转换 - 但是,编译器也允许这种转换.
Likewise, according to the JLS it should not be possible to cast from byte
to char
, because that (according to 5.1.4) requires a widening primitive conversion and a narrowing primitive conversion - however, this cast is also allowed by the compilers.
谁能给我指点一下?
自从提出这个问题,我已经提交了一个 错误报告 与 Oracle.他们的回应是,这是JLS 中的一个小故障".
since asking this, I have filed a bug report with Oracle. Their response is that this is a "glitch in the JLS".
推荐答案
我认为你是对的,编译器是对的,规范是错的....
I think you are right, the compilers are right, and the spec is wrong....
这编译:(Object)45
而这不会:(Long)45
理解编译器行为(包括我正在使用的 Intellij)的唯一方法是将 Casting Conversion 修改为与赋值转换和方法调用转换一致:
The only way to make sense of the compilers' behavior (including Intellij I'm using) is if Casting Conversion is modified to agree with Assignment Conversion and Method Invocation Conversion:
拳击转换(第 5.1.7 节)可选地随后加宽参考转换
a boxing conversion (§5.1.7) optionally followed by widening reference conversion
拆箱转换(第 5.1.8 节)可选地后跟扩大原始转换.
an unboxing conversion (§5.1.8) optionally followed by a widening primitive conversion.
加上
- 扩大和缩小原始转换
规范确实说强制转换比赋值或方法调用转换更具包容性:强制转换可以进行除字符串转换或捕获转换之外的任何允许的转换"
The spec did say "casting conversions are more inclusive than assignment or method invocation conversions: a cast can do any permitted conversion other than a string conversion or a capture conversion"
这篇关于Java 转换:是编译器错了,还是语言规范错了,还是我错了?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!