为什么无法使用父引用访问子字段
class A { int super_var = 1; } class B extends A { int sub_var = 2; } public class Demo{ public static void main(String []args){ A a = new B(); System.out.print(a.sub_var); //compile error } }
为什么这会以编译错误结束? 引用(a)引用B的对象它有sub_var那么为什么它受到限制? 为什么参考(a)只能访问A中的字段?
假设您有这些课程:
public class Animal() { // ... } public class Fish extends Animal() { public void swim() {...} }
如果你宣布了一个Animal
:
Animal x = new Fish();
你调用了swim()
方法
x.swim();
你期望它能起作用吗? 我不这么认为,因为不是每个动物都可以游泳。 这就是为什么你必须明确指出动物x
是Fish
:
((Fish) x).swim();
在您的情况下 ,如果您想调用该方法,则应指定(在技术上,它称为强制转换 )类型:
System.out.print(((B)a).sub_var);
注意:
- 这适用于方法和变量。 我在示例中使用了一种方法,因为它更具说明性。
编辑:
我们来看看这个例子:
Animal x; if (some_condition) x = new Fish(); else x = new Cat(); x.swim();
存在这种限制,因为Java在执行时不知道分配给x的对象是否具有方法swim()
。 因此,为了避免这种情况,您必须转换为相应的类型以调用超类中不存在的方法。
起初它确实听起来应该有效。 (在某些语言中它可能会这样做。)但想想这个例子:
public class Demo { public static void main(String []args){ A a = new B(); print( a ); } public static void print( A arg ) { System.out.print(arg.sub_var); //compile error } }
这在function上做同样的事情,但打印在另一种方法。 如果您的版本有效,那么这个版本也可以使用。
但是,如果有人这样做呢?
Demo.print( new A() );
这应该失败,因为A
没有sub_var
。 它将不得不抛出某种运行时错误。
因此,Java中的设计决策不允许这样做,如果您将局部变量/ field / method参数声明为类型A
,那么您只能访问保证A
或子类的每个对象都具有的内容。
如果要访问更多,则需要将其强制转换为子类,如果在不适合的对象上尝试, 则会抛出exception。
A a = new A(); System.out.print(((B)a).sub_var); //ClassCastException is thrown here
您不能使用父对象A的引用访问B成员。
而是更改您的println
语句,如下所示,访问,
System.out.print(((B)a).sub_var);
在父类中是否有一个名为sub_var的变量? 不,这就是你得到错误的原因 –
sub_var cannot be resolved or is not a field
看到这个
System.out.print(a.super_var); //okay System.out.print(a.sub_var); //compile error
您创建一个B类型的对象并将其分配给A类型的变量。类型A不声明sub_var。 此字段仅在类型B中声明。编译器仅查看在类型A中声明的内容,尽管该变量实例化为类型B的对象。
如果要访问sub_var,则必须将a转换为B.
System.out.println(((B)a).sub_var);
sub_var
在class B
,因此您只能通过class B
的引用进行访问。 编译器A a = new B();
表示a
是class A
的实例。