我认为您无法将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!?
}
}
答案 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( )方法是安全的。