java使用子类型强制转换的一些硬性“规则”是什么?
我在为即将到来的Java期末考试准备一些练习考试时,遇到了这个问题
Consider the following class definitions and indicate whether 'Test.main()' would compile successfully. If it does compile, indicate whether it would run successfully or if not, indicate what Exception would be thrown.
public class A {
public int method(int[] a) {...}
}
public class B extends A {
@Override
public int method(int[] a) {...}
}
public class C extends B {
@Override
public int method(int[] a) {...}
public void otherMethod() {...}
}
public class Test {
public static void main(String[] args) {
A a = new C();
B b = new B();
b = (B) a;
}
}
我以为是考试。main()会编译,但会抛出一个运行时异常,因为a是实际类型C,我们正试图将其转换为类型B。情况并非如此,因为答案说这是可以的
我对演员的规则非常困惑,因为其中涉及的层次比两个级别更深。课堂幻灯片上并没有这种信息
那么,如果这类问题在考试中突然出现,有哪些硬性的“规则”需要牢记
# 1 楼答案
要完全理解这个看似简单的问题所涉及的问题需要很长时间,而且需要一个人理解the Java language specification,但一个像样的理解也许就在眼前@JBT的思想具体化也很有用
一些术语和简化如下:
A
、B
和C
类)。我们将源类型表示为Source
,将目标类型表示为Target
李>=
符号的右侧,目标类型的变量显示在其左侧。因此,您可以:Target t = (Target) s
,其中s
是Source
类型的变量李>现在,适用的规则according to the JLS(经过一些简化后)是:
(实际的严格规则是:
If T is a class type, then either |S| <: |T|, or |T| <: |S|
。否则,会发生编译时错误。|S|
表示S
的擦除,而<:
表示是关系的子类。)现在,您的类
A
、B
和C
创建以下层次结构:C <: B <: A
:main
方法可以有效地表示为:现在,按照上面适用的规则,由于
b
(即Target
)的类型是B
的一个子类A
(即Source
),所以(2)中的赋值应该编译得很好,因为您正在将从源类(A
转换为目标类(B
),该类位于关系的子类中根据(1),变量
a
的运行时类型实际上是C
。由于C
是B
的一个子类,任何类型C
(源)的变量都可以分配给类型为B
(目标)的变量,使强制转换在运行时成功(即,使其而不是抛出ClassCastException
)。这被称为Liskov Substitution Principle# 2 楼答案
当存在复杂的层次结构时,请尝试将其绘制出来,以便更清晰:
a
的底层类型是C
。然而,C
可转换为B
和{C
继承自B
,而B
继承自A
基本上,引用类型转换是否成功的一般规则如下:
假设我们有这个代码:
这将失败,因为我们需要逆箭头的方向从
A
到B
那么,您如何知道强制转换是否会在编译时失败呢
这很容易。只需检查
Y
的变量类型是否(不是底层类型!)与X
无关例如:
但是,如果
Y
的变量类型与X
相关,则它可以很好地编译: