对编译器处理继承和方法调用感到困惑

时间:2018-10-07 16:12:31

标签: java class oop inheritance compiler-construction

在阅读了有关继承和方法调用以及编译器如何处理这些信息之后,我感到困惑。因此,如果有人看看我如何看待事物并在错误的地方纠正我,我将不胜感激。

首先让我们看一下以下代码:

A级

public class A {

    public void testMethodA(String a) {
        System.out.println(a);
    }

}

B类:

public class B extends A {


}

主要

public class Main {

    public static void main(String[] args) {
        B b = new B();
        b.testMethodA("test");
    }

}

现在让我们看一下我对事物的理解方式(如果我错了,请纠正我):

  1. 在继承期间,创建子类对象时,您正在创建一个对象,该对象接收来自所有超类的所有字段和方法。因此,在编译期间,子类的字段和方法不会从超类转移到子类(来源:Does an instance of superclass get created when we instantiate an object?
  2. 在编译期间,编译器检查是否在声明的引用类型中定义了支持参数类型的to方法。因此,在示例中:A a = new A(); a.testMethod("test")将在编译期间检查是否在类 A 中定义了 testMethod(),该类可以接收 String < / strong>作为参数。 (来源:How does java compiler choose correct methods and variables in inheritance
  3. 运行时发生时,从存储在变量 a 中的实际对象调用 testMethod(),该对象并不总是 A类型的对象由于多态性。

现在是实际问题:

根据上述逻辑和代码,我预计在编译期间会出现无法解析方法错误。原因是在编译期间,编译器检查 B 类是否存在 testMethodA(String)。但是,此方法是从 A 类继承的,并且据我了解,继承的方法不会在运行时传递给子类,而是传递给子类的对象。因此,如果在编译期间 B 类中不存在 testMethodA(String),那么编译器又如何才能成功地编译代码?当然,它不会检查该方法的对象,因为尚未创建该对象。

此问题未在“可能的答案”中回答,因为该线程是我自己在描述此问题时标记为知识来源的线程。

1 个答案:

答案 0 :(得分:1)

我认为,您的主要误解在于第2点。

  

在编译期间,编译器检查被调用的方法是否   支持在声明的引用类型中定义的参数类型。

最好阅读:

在编译期间,编译器会检查是否在声明的引用类型中定义了支持参数类型的被调用方法或其沿整个树的超类型之一或已实现的接口

编译器知道B的任何实例(是A的子类)将具有方法testMethodA(),该方法可以是从超类A继承的方法,也可以是子类中重写的一个,因此可以安全地调用该方法。

您使用“ pass”一词来描述字段和方法从超类到子类的继承。这个措辞听起来让我感到困惑,因为它暗示了某些重复过程,而该过程只是部分发生。对于实例字段,这或多或少是可以的,因为子类的每个实例都将获得超类字段和子类字段的单独副本。但是方法不会被复制到实例,它们会“保留”在定义它们的类中(如果添加方法,实例不会占用更多内存)。在内部,Java Runtime维护某种查找表,以查找给定实例类的适当方法版本。

因此,我认为“将方法传递给子类对象”这一措词与实际过程不符。