为什么在使用超类引用调用子类方法时会出现编译时错误?

时间:2016-06-16 08:12:16

标签: java polymorphism

我知道在方法覆盖的情况下会发生多态。 但我对下面的内容感到有些困惑。

class A {
    public void hi() {
        System.out.println("A "+this.getClass().getName()); 
    }
}

class B extends A {
    public void bye() {
        System.out.println("B "+this.getClass().getName());
    }
}

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        A a = new B();
        a.hi();
        a.bye();
    }
}

输出:

Main.java:35: error: cannot find symbol
        a.bye();
         ^
  symbol:   method bye()
  location: variable a of type A
1 error

为什么会出现编译时错误?

a = new B()中,B类对象是在运行时创建的,因此a是一个指向B类型对象的引用变量。

现在,如果我们调用B的类方法bye(),为什么它是编译器时间错误?

7 个答案:

答案 0 :(得分:2)

a变量可能在运行时包含类A的实例或A的任何子类。因此,您只能为该变量调用类A的方法。

编译器在确定哪些方法调用有效时,只关心变量的编译时类型。

答案 1 :(得分:2)

变量a的声明类型是A.编译器不知道(也不应该知道)它在运行时的具体类型是什么B.它只知道它是A,并且A中没有bye()方法。

完成的重点

A a = new B();

而不是

B a = new B();

要清楚地说a是A,并且可以有任何具体类型,只要conrete类型扩展A.如果你以后找到更好的A实现,你必须能够将该行更改为

a a = new BetterImplementation();

并编译代码。

答案 2 :(得分:0)

多态性基本上是一个对象采取多种形式的能力。由于您的父类是指子类对象,因此它是多态的。

Main.java:35: error: cannot find symbol
        a.bye();
         ^
  symbol:   method bye()
  location: variable a of type A
1 error

您收到此错误是因为您尝试从超类引用中调用子类的方法。

在这里,您将subClass对象ref分配给超类,这很好。 但超类只能调用它自己已知的方法和数据。

A a = new B();
 a.hi(); // member of super class
 a.bye(); // Not a member a super class

答案 3 :(得分:0)

将新的B实例分配给类型为A的引用,就像让它佩戴唯一的方法定义的A眼镜一样。那就是你得到了A所描述的界面。即使该实例具有bye的实现,您也只能访问hi

答案 4 :(得分:0)

理解这一点的一个简单方法是A a实际上可能指向B的对象,但在编译期间,编译器并不知道。

编译器只检查引用,即' a'并看看它的班级,即' A'有一个方法,它的参考' a'正打算打电话。

在您的情况下,参考' a'没有一个名为bye()的方法,所以根据编译器不能进行这样的调用,这就是你看到错误的原因。

答案 5 :(得分:0)

我认为你已经从其他答案得到了你的多态性问题的答案。除此之外,您还可以通过类型转换使代码以这种方式工作。

(B)a.bye();

This是一个很好的解释,您可以阅读有关引用与对象类型的内容。 this是关于投射的好文章。

答案 6 :(得分:0)

您只能从父类类型访问父类方法。

A a = new B();

解决方案1:

将父级更改为子级(B b = new B ())并调用B方法。

解决方案2:

检查parent是否是Child对象的实例。如果是,则将父项转换为Child并调用方法。

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        A a = new B();
        a.hi();
        if ( a instanceof B){       
            ((B)a).bye();
        }
    }
}

输出:

A B
B B

查看instanceof

上的oracle文档页面
  

instanceof运算符将对象与指定类型进行比较。您可以使用它来测试对象是否是类的实例,子类的实例或实现特定接口的类的实例。