确定实际调用了哪个覆盖方法

时间:2017-06-10 10:33:27

标签: java

当子类对象被转换为其超类时,例如

Superclass obj = new Subclass();

并定义了类

public class Superclass{
    public void thisMethod(){
        System.out.println("Superclass version was executed");
}

public class Subclass extends Superclass{
    public void thisMethod(){
        System.out.println("Subclass version was called");
}
    public void newMethod(){
        System.out.println("blah");
  }
}

当调用obj.thisMethod()时,我得到Subclass version was called作为输出,这显然意味着在子类中定义的此方法的版本(原始超类对象不能的版本"执行")被调用,虽然声明的类型是超类,是吗? 所以,即使子类方法是在obj上执行的, 调用obj.newMethod()时,出现编译错误。

基本上,为什么子类中定义的thisMethod()版本是通过超类对象obj调用的?我知道obj的实际类型仍然是Subclass,所以很自然地应该调用新版本,但是,我不应该调用obj.newMethod()吗?

感谢大家的解释(:

编辑:意味着在标题中覆盖*

3 个答案:

答案 0 :(得分:7)

  

基本上,为什么子类中定义的thisMethod()的版本是通过Superclass对象obj调用的?

因为它基本上是继承点 - 它允许实现覆盖,而调用代码不需要知道正在使用哪个实现。以InputStream为例 - 您可以使用InputStream进行编码,然后无论您是否通过FileInputStreamByteArrayInputStream等,相同的代码都会有效。在抽象类或接口的情况下,您可能正在调用在编译时类型中没有具有任何实现的方法 - 但它保证会出现这样的情况。是在执行时使用的具体对象类型的实现。

  

我知道obj的实际类型仍然是Subclass,所以很自然地,应该调用新版本,但是,我不应该调用obj.newMethod()吗?

不,因为obj编译时类型为Superclass。区分变量的编译时类型(确定哪些方法可用)和对象的执行时类型非常重要变量的值引用,它确定实际调用哪些方法实现。

这只是一个非常简短的描述 - 你应该阅读一本好的Java书籍关于继承的章节以获取更多细节。

答案 1 :(得分:1)

理论上obj是指向Superclass对象的Subclass引用。

对于编译器obj只是Superclass,因此可以调用所有Superclass方法,例如thisMethod,编译器不知道对象的类型,只知道引用的类型,因此编译器将拒绝newMethod,因为它无法证明此方法存在。

但是在运行时,对象的类型用于分派方法而不是引用类型,因此thisMethod将被解析为Subclass的版本。

现在,如果我们知道运行时对象的类型为Subclass,我们想告诉编译器这个,我们做一个强制转换:

Subclass subobj = (Subclass) obj;

之后,编译器知道subobj类型为Subclass,并且接受调用newMethod,转换只是编译器的信息,并且不会改变任何内容对象objobj不是Subclass,前一个语句将在运行时抛出ClassCastException

答案 2 :(得分:0)

超类obj = new Subclass()在这个定义中你只能在Superclass.And中的公开方法实际上指向Subclass对象,当你调用任何方法时它会调用子类实现