Java中的强制转换和继承
考虑以下简单代码:Java中的强制转换和继承,java,inheritance,casting,Java,Inheritance,Casting,考虑以下简单代码: 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;
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,对吗?因此,第3行不应该在运行时抛出任何异常吗
a1
是A
元素的数组。由于B
扩展了A
,因此B
的所有实例也是A
的实例,但并非A
的所有实例都是B
的实例。您可以定义一个类C
,该类也扩展a
,并将该类的实例分配给a1
数组。这些实例不是B
的实例
因此,您不能将A
元素数组强制转换为B
元素数组。您说的“B是-A”是正确的,这就是为什么i) 当你把a=b放进去时,没有问题
ii)语句#3在编译时没有问题
但是您不能说“A是-A B”,因此运行时异常。您忘记了,数组本身就是类,它们有自己的强制转换和赋值规则 考虑这一点:
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[],但不能反过来指定。请花点时间格式化您提供的代码。现在读起来真的很难,一行没有缩进和多个语句。请记住,堆栈溢出的目的是创建一个高质量问题和答案的存储库-投入时间使您的问题真正具有高质量。“因此它满足条件B is-a,正确吗?”正确。但你需要的是“A是-A是-B”-但你没有。我猜混淆就在这里:
a1=a;a=b;//1
-通过更改参考a
您没有更改a1
。它仍然指向相同的A[]
。但是代码编译得很好。它在运行时抛出异常。但是,假设我创建了这样一个数组:-TestClass c[]=newtestclass[20]
。现在,当我尝试b=(b[])c
时,它给出了不兼容的类型。为什么会有不同的行为?@Shashwat您可以将B[]实例分配给a[]变量(就像您可以将B实例分配给a变量一样)。因此,如果运行时类型匹配,则在运行时将A[]变量强制转换为B[](或将A变量强制转换为B)可能会成功。但是,TestClass[]永远不能强制转换为B[],因为TestClass不是B的子类,B也不是TestClass的子类。这就是为什么编译器不允许它。让我直说吧。虽然你不能做b=(b[])a1
、b
和a1
是兼容的类型,这是编译器所寻找的所有类型,因此它可以正确编译,尽管实际上不可能将b
指定为等于a1
。如果我错了,请纠正我,@Shashwatb=(b[])a1如果在此行之前有一行将B[]
的实例分配给a1
(例如a1=new B[10];
),则code>可以在运行时成功。编译器不分析a1
的运行时类型。它只分析其编译时类型,以确定强制转换是否可以在运行时成功。