Java中的强制类型转换和继承

4

考虑这段简单的代码:

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行不应该抛出任何异常,是吗?

1
请花些时间对您提供的代码进行格式化。目前,由于没有缩进和多个语句在一行上,阅读起来非常困难。请记住,Stack Overflow 的目的是创建一个高质量问题和答案的存储库 - 投入时间使您的问题真正高质量。 - Jon Skeet
1
所以它满足条件B IS-A A,对吗?正确。但你需要的是"A IS-A B" - 但你没有这个。我猜混淆是从这里开始的:a1 = a; a = b;//1-通过更改引用a,您不会更改a1。它仍然指向同一个A [] - Fildor
3个回答

7
a1是由A元素构成的数组。由于B扩展了A,所以所有B的实例也都是A的实例,但不是所有A的实例都是B的实例。您可以定义一个扩展A的类C并将该类的实例分配给a1数组。这样的实例不是B的实例。

因此,您无法将A元素的数组强制转换为B元素的数组。


但是代码编译没有问题。它在运行时抛出异常。然而,假设我像这样创建了一个数组:TestClass c[] = new TestClass[20]。现在当我尝试 b = (B[]) c 时,它会给出不兼容类型的编译错误。为什么会有不同的行为? - dumbPotato21
@Shashwat 你可以将一个B[]实例分配给一个A[]变量(就像你可以将一个B实例分配给一个A变量)。因此,如果运行时类型匹配,则将A[]变量转换为B[](或将A变量转换为B)可能会在运行时成功。但是,TestClass[]永远不能转换为B[],因为TestClass不是B的子类,B也不是TestClass的子类。这就是编译器不允许的原因。 - Eran
让我来澄清一下。虽然你不能执行 b = (B[]) a1;,但是 ba1 是兼容的类型,这就是编译器所寻找的,因此它可以正确编译,尽管将 b 赋值为 a1 实际上是不可能的。如果我错了,请纠正我。 - dumbPotato21
@Shashwat 如果在这行代码之前有一行将 B[] 的实例分配给 a1(例如 a1 = new B[10];),那么 b = (B[]) a1; 可能会在运行时成功。编译器不会分析 a1 的运行时类型,它只分析其编译时类型以确定转换是否可以在运行时成功。 - Eran

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[],但反过来不行。

0
你说“B IS-A A”是正确的,这就是为什么:
i)当你把a = b;时没有问题;
ii)语句#3在编译时没有问题。

但是你不能说“A IS-A B”,因此会出现运行时异常。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接