考虑这个简单的代码:
class A {}
class B extends A {}
public class TestClass {
public static void main(String args[]) {
A[] a, a1;
B[] b;
a = new A[10];
a1 = a;
b = new B[20];
a = b; // 1
b = (B[]) a; // 2
b = (B[]) a1; // 3
}
}
仔细查看我评论1,2和3的行。编译期间将允许第1行,因为赋值是从子类引用到超类引用完成的。
第2行中的强制转换是必需的,因为超类引用被分配给子类引用变量。这在运行时工作,因为a引用的对象实际上是B(第1行)的数组。
现在,这就是我的困惑所在:第3行将抛出java.lang.ClassCastException。现在,这意味着在运行时,程序意识到实际对象不是B的数组,而是A的数组。
这正是我不明白的地方。 B不延伸A吗?所以它满足条件B IS-A A,对吗?因此,第3行不应该在运行时抛出任何异常吗?
答案 0 :(得分:7)
a1
是一个A
元素数组。自B
扩展A
以来,B
的所有实例都是A
的实例,但A
的所有实例都不是B
的实例。您可以定义一个类C
,它还扩展A
并将该类的实例分配给a1
数组。此类实例不是B
的实例。
因此,您无法将A
元素数组转换为B
元素数组。
答案 1 :(得分:2)
你忘记了,数组本身就是类,它们有自己的转换和赋值规则。
考虑一下:
A[] aa = new A[0];
B[] bb = new B[0];
System.out.println(aa.getClass());
System.out.println(bb.getClass());
System.out.println(aa.getClass().isAssignableFrom(bb.getClass()));
System.out.println(bb.getClass().isAssignableFrom(aa.getClass()));
输出:
class [Lstuff.small.Try47$A;
class [Lstuff.small.Try47$B;
true
false
因此,A []变量确实可以被赋予B [],但不是相反。
答案 2 :(得分:0)
你说对了#34; B IS-A A"这就是为什么
i)当你输入a = b时没有问题;
ii)语句#3
但你不能说"一个IS-A B",因此是运行时例外。