将父级转换为子级 - 数组中的奇怪行为

时间:2017-07-03 14:56:38

标签: java arrays casting polymorphism parent-child

我认为您无法将Parent投射到Child,并且只能将Child投射到Parent。或者至少如果你这样做,你就不会被允许访问孩子的功能。

然后我看到Java将允许我显式地将父级转换为子级:

a=(B)a;

但不允许

bArray[0]=a

a.testB();

但这没关系:

bArray[1]=(B)a;

这是这样的:

bArray[1].testB();

有人可以解释一下这里发生了什么!?父类如何被赋予子类的功能?为什么第一次尝试放入数组不起作用,但第二次尝试呢?不应该是一样的吗?

class A {
    public void testA() {
    }
}

class B extends A {
    public void testB() {
    }
}

public class polymorphicObjects {
    public static void main(String[] args) {
        B bArray[] = new B[5];      
        A a = new A();
        A ab = new B();

        a = (B)a; //didnt think you could do this
        bArray[0] = a; //but if I can the why doesnt this work?
        a.testB();  //or this
        bArray[1] =(B)a; //but this does work
        bArray[1].testB(); //and so does this!? 
    }
}

2 个答案:

答案 0 :(得分:0)

运行bArray[1].testB();实际上有效吗?那应该至少抛出一个ClassCastException。在testB()方法中添加print语句应该有所帮助。

所以在这里,你说a = (B)a;非常明确地将a转换为B类,但它实际上并不意味着什么。

考虑到这一点,这在第一行bArray[0] = a;中不起作用,因为它不再显式转换,因此编译器会抱怨你提供的类型不匹配。

在后续行bArray[1] = (B)a;中,您明确告诉编译器a类型为B,因此它不会咆哮...尽管对方法testB()的调用应该在运行时失败。

答案 1 :(得分:0)

在Java中,强制转换具有非常特定的含义(例如,与C语言不同)。您必须区分对象实际具有的类,以及编译器对某个表达式的类的看法。

Casting不会更改实际的对象类,只会更改编译器对表达式类的看法。

让我们来看看你的代码:

new A()将始终为您提供A类对象,编译器知道。

将它存储到声明为A类的引用变量a中,因此从声明(而不是new A()表达式)中,编译器知道变量a具有A类(也允许子类)。

使用强制转换表达式(B) a,您不会更改有关a中存储的对象的任何内容,只需向编译器断言您作为开发人员知道存储在{{{ 1}}是B类型(在您的情况下,它不是真的,它是A,而不是B)。编译器不够智能,因此他将表达式a视为有效且属于B类。他允许您从A转换为B,因为B是A的子类,所以类的变量A可能完全包含B类的对象(例如(B) a完全可以)。在运行时,JVM将检查实际的对象类并引发ClassCastException,因为它发现它不是来自子类B的A。

使用A a = new B();,您可以将同一个对象存储回相同的变量中。

你问的是a = (B) a;这不能编译,因为对于编译器,bArray[0] = a;包含一个A类对象,并且数组需要一个B. a将编译,但是抛出只要变量仍包含类A的相同对象,就会运行ClassCastException。

并且bArray[1] = (B) a;编译,因为编译器知道在bArray[1].testB();中所有元素都是B类,而B类有这种方法。由于尝试将非B类的对象存储到bArray中将无效(在编译时bArray或在运行时bArray[0] = a;),因此调用testB( )方法是安全的。