【问题标题】:Confused about compiler handling inheritance and method invocation对编译器处理继承和方法调用感到困惑
【发布时间】:2018-10-07 16:12:31
【问题描述】:

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

我们先来看看下面的代码:

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. 在编译期间,编译器检查是否在声明的引用类型中定义了支持参数类型的被调用方法。所以在示例中:A a = new A(); a.testMethod("test") 它会在编译期间检查是否在可以接收 String 的类 A 中定义了 testMethod() > 作为论据。 (来源:How does java compiler choose correct methods and variables in inheritance
  3. 运行时,testMethod() 会从存储在变量 a 中的实际对象调用,该对象并不总是 A 类型的对象 由于多态性。

现在的实际问题:

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

“可能的答案”中没有回答这个问题,因为这个主题是我在描述这个问题时自己标记为知识来源的主题。

【问题讨论】:

  • 为什么编译器不应该检查超类(或接口)是否定义了类使用的方法?这个结论对我来说毫无意义。
  • 编译器检查类及其所有超类和接口。
  • Joakim 因为如果我不知道编译器有这样的行为,我怎么能提到呢?
  • 感谢您的回答彼得劳瑞

标签: java class oop inheritance compiler-construction


【解决方案1】:

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

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

最好这样读:

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

编译器知道B 的任何实例(作为A 的子类)都会有一个方法testMethodA(),或者是从超类A 继承的方法,或者是从子类中重写的方法,所以调用该方法是安全的。

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

所以我认为,“将方法传递给子类对象”的措辞不符合实际过程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多