java - 为什么这段代码在编译时没有发出 `ClassCastException` 警告?
问题描述
我已经看到了这个问题,但它似乎没有回答下面的两种情况,也没有参考任何进一步的文档,我很想阅读。
我有以下代码片段:
public static void main(String[] args) {
// compile-time OK
// run-time ClassCastException
Child noWarnings = (Child) getParent();
// vs...
// compile-time failure
Child compileTimeFailure = new Parent();
}
private static Parent getParent() {
return new Parent();
}
private static class Parent { }
private static class Child extends Parent { }
代码片段第 4 行的代码不会产生警告,但会产生ClassCastException
. 为什么编译器无法对此进行类型检查?
如果我们添加一个间接层,这会变得更加奇怪:
public static void main(String[] args) {
// compile-time OK
// run-time ClassCastException
Boxed noWarnings = new Boxed((Child) getParent());
// vs...
// compile-time OK, but warning is emitted correctly
// run-time ClassCastException
Boxed classCastWarning = new Boxed((Child) new Parent());
}
private static Parent getParent() {
return new Parent();
}
private static class Boxed {
public Boxed(Child data) {
}
}
private static class Parent { }
private static class Child extends Parent { }
编译器不允许第一个示例,但允许第二个示例,这似乎不直观。
任何关于这两种情况的信息都将受到欢迎。
解决方案
为什么编译器无法对此进行类型检查?
有些 Parent
实例是 的实例Child
,因为所有Child
的 s 都是Parent
s。编译器不知道将返回的实例是否为 a Child
;但它可能是。所以它允许它。
事实上,正如Stephen C 指出的那样,JLS 不允许编译器将此称为编译错误。
具体来说,语言规范说:
如果无法通过强制转换(第 5.5 节)将操作数的编译时类型转换为强制转换运算符指定的目标类型,则会发生编译时错误。
(它还描述了在转换表达式中发生编译时错误的另一种情况;但是这些不适用于这里,因为没有一个或多个AdditionalBound
术语)。
Parent
可以Child
通过缩小引用转换来转换,因此不会发生编译时错误。
Boxed classCastWarning = new Boxed((Child) new Parent());
这显然会失败。new Parent()
不是 的实例Child
,而是 的实例Parent
。
但是编译器实际上并没有考虑强制转换new Parent()
的上下文中的任何事情,除了它是一个 type 的表达式Parent
,它必须允许你强制转换为一个Child
.
但这并不是说不允许诸如 IDE 之类的工具给你一个警告(甚至是一个错误,如果你有这样的配置):通过静态分析很清楚,这new Parent()
将是一个Parent
精确的实例(因为这就是全部new Parent()
),因此将其转换为子类将失败。您的工具可以告诉您规范中未具体涵盖的内容。
推荐阅读
- python - AWS Athena PyAthena AccessDeniedException
- c++ - 复制联合对象时,是否创建了成员子对象?
- html - 当移动设备小于 1000px 时,强制 CSS 对 1000px 应用媒体查询
- c - 如何让计数器在这个 C 程序中工作?
- eclipse - Eclipse IDE 在“分析项目”期间发生内部错误。com/yakode/java/search/c
- java - 加载 RecyclerView 时 Android 模拟器崩溃
- windows - 如何使用 docker 在 Windows Server 2019 中使用 nginx 设置反向代理?
- julia - 用于子图(节点/顶点和边)而不更改或重新标记节点索引的 Julia 模块?
- c - Linux 上的 gcc 如何知道包含 printf 函数的是 libc.so.6?
- react-native - 清除间隔功能在本机反应中不起作用