Mik*_*ski 53 java casting compiler-errors javac
如果我尝试将 a 转换String为 a java.util.Date,Java 编译器会捕获错误。那么为什么编译器不将以下内容标记为错误呢?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Run Code Online (Sandbox Code Playgroud)
当然,JVMClassCastException在运行时抛出 a ,但编译器不会标记它。
行为与 javac 1.8.0_212 和 11.0.2 相同。
Zab*_*uza 87
演员阵容在技术上是可行的。javac 无法轻易证明您的情况并非如此,并且 JLS 实际上将其定义为有效的 Java 程序,因此标记错误将是不正确的。
这是因为List是一个接口。因此,您可以拥有一个Date实际实现List伪装为List此处的a 的子类-然后将其强制转换Date为完全可以。例如:
public class SneakyListDate extends Date implements List<Foo> {
...
}
Run Code Online (Sandbox Code Playgroud)
进而:
List<Foo> list = new SneakyListDate();
Date date = (Date) list; // This one is valid, compiles and runs just fine
Run Code Online (Sandbox Code Playgroud)
检测这样的场景可能并不总是可能的,因为如果实例来自例如方法,则需要运行时信息。即使这样,编译器也需要付出更多的努力。由于类树根本无法匹配,编译器只会阻止绝对不可能的强制转换。正如所见,情况并非如此。
请注意,JLS 要求您的代码是有效的 Java 程序。在5.1.6.1 中。Allowed Narrowing Reference Conversion它说:
如果以下所有条件都为真,则存在从引用类型
S到引用类型的缩小引用转换:T
- [...]
- 一个有下列情形适用:
- [...]
S是接口类型,T是类类型,T不命名final类。
因此,即使编译器可以确定您的情况实际上是不可能的,也不允许标记错误,因为 JLS 将其定义为有效的 Java 程序。
只允许显示警告。
Ste*_*n C 16
让我们考虑对您的示例进行概括:
List<String> strList = someMethod();
Date d = (Date) strList;
Run Code Online (Sandbox Code Playgroud)
这些Date d = (Date) strList;是不是编译错误的主要原因。
的直观的原因是,编译器不(通常)知道精确的类型由该方法调用所返回的对象的。有可能除了是实现 的类之外List,它也是的子类Date。
该技术的原因是,Java语言规范“允许”的狭窄基准转换对应于这种类型的演员。根据JLS 5.1.6.1:
“如果满足以下所有条件,则存在从引用类型
S到引用类型的缩小引用转换T:”...
5) "
S是接口类型,T是类类型,T不命名final类。"...
在另一个地方,JLS 还说在运行时可能会抛出异常......
请注意,JLS 5.1.6.1 的确定仅基于所涉及变量的声明类型,而不是实际的运行时类型。在一般情况下,编译器不知道也不可能知道实际的运行时类型。
那么,为什么 Java 编译器不能确定强制转换不起作用呢?
在我的示例中,someMethod调用可以返回多种类型的对象。即使编译器能够分析方法体并确定可以返回的精确类型集,也没有什么可以阻止有人更改它以返回不同类型......在编译调用它的代码之后。这就是 JLS 5.1.6.1 所说的内容的基本原因。
在您的示例中,智能编译器可以确定强制转换永远不会成功。并且允许发出编译时警告来指出问题。
那么为什么不允许智能编译器说这是一个错误呢?
因为 JLS 说这是一个有效的程序。时期。任何将此称为错误的编译器都不符合 Java 标准。
此外,任何拒绝 JLS 和其他编译器认为有效的Java 程序的编译器都会阻碍 Java 源代码的可移植性。
| 归档时间: |
|
| 查看次数: |
2230 次 |
| 最近记录: |