为什么无法使用父引用访问子字段

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(); 

你期望它能起作用吗? 我不这么认为,因为不是每个动物都可以游泳。 这就是为什么你必须明确指出动物xFish

 ((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_varclass B ,因此您只能通过class B的引用进行访问。 编译器A a = new B(); 表示aclass A的实例。