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

时间:2014-03-22 20:59:32

标签: java inheritance

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的Object它有sub_var,为什么它受到限制?为什么参考(a)只能访问A?

中的字段

6 个答案:

答案 0 :(得分:5)

让我们说你有这些课程:

public class Animal() {
    // ...
}

public class Fish extends Animal() {
    public void swim() {...}
}

如果您宣布Animal

Animal x = new Fish();

您调用了swim()方法

x.swim();

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

((Fish) x).swim();

在您的情况下,如果您想调用该方法,则应指定(在技术上,它称为 cast )类型:

System.out.print(((B)a).sub_var);

注意:

  • 这与方法和变量类似。我在示例中使用了一种方法,因为它更具说明性。

修改

让我们看看这个例子:

Animal x;

if (some_condition)
    x = new Fish();
else
    x = new Cat();

x.swim();

存在这种限制,因为Java不知道在执行时分配给x的对象是否具有方法swim()。所以为了避免这种情况,你必须转换为相应的类型来调用一个不存在于超类中的方法。

答案 1 :(得分:1)

起初听起来确实应该有效。 (在某些语言中它可能会这样做。)但想想这个例子:

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
    }
}

这在功能上做同样的事情,但打印是另一种方法。如果您的版本有效,那么这个版本也可以使用。

但如果有人这样做呢?

Demo.print( new A() );

这应该会失败,因为A没有sub_var。它将不得不抛出某种运行时错误。

因此,Java中的设计决策不允许这样做,如果您将局部变量/ field / method参数声明为类型A,那么您只能访问每个对象A的内容。或者保证子类有。

如果您想要访问更多内容,则需要将其强制转换为子类,如果您在不适合的对象上尝试,抛出异常。

A a = new A(); 
System.out.print(((B)a).sub_var); //ClassCastException is thrown here 

答案 2 :(得分:0)

您无法通过父对象A的引用来访问B成员。

而是更改您的println语句,如下所示,

System.out.print(((B)a).sub_var);

答案 3 :(得分:0)

父类中是否有一个名为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

答案 4 :(得分:0)

创建B类型的对象并将其分配给A类型的变量。类型A不声明sub_var。此字段仅在类型B中声明。编译器仅查看在类型A中声明的内容,尽管该变量实例化为类型B的对象。

如果要访问sub_var,则必须将a转换为B.

System.out.println(((B)a).sub_var);

答案 5 :(得分:0)

sub_var位于class B,因此您只能通过class B的引用进行访问。编译器A a = new B();表示aclass A的实例。