繁体   English   中英

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

[英]Why do I get a compile-time error when calling a subclass method using superclass reference?

我知道在方法重写的情况下会发生多态。 但是我对以下内容有些困惑。

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() ,为什么它是编译器错误?

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

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

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

整个工作要做

A a = new B();

并不是

B a = new B();

明确表示a是A,并且可以有任何具体类型,只要conrete类型扩展了A。如果稍后找到更好的A实现,则必须能够将该行更改为

A =新的BetterImplementation();

并编译代码。

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

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

将新的B实例分配给类型A的引用就像使它戴上了仅在A中定义的方法。 那就是您在A处描述的接口。 即使该实例具有bye的实现,您也只能访问hi

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

编译器仅检查引用即“ a”,并查看其类(即“ A”)是否具有其引用“ a”正在尝试调用的方法。

在您的情况下,引用“ a”没有名为bye()的方法,因此根据编译器,无法进行此类调用,这就是您看到该错误的原因。

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

(B)a.bye();

是一个很好的解释,可帮助您阅读有关引用与对象类型的信息。 是一篇有关铸造的好文章。

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

A a = new B();

解决方案1:

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

解决方案2:

检查父对象是否为子对象的实例。 如果是,则将父项强制转换为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运算符将对象与指定类型进行比较。 您可以使用它来测试对象是实现特定接口的类的实例,子类的实例还是类的实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM