【问题标题】:java overloaded method invocation order by an object at runtime对象在运行时的java重载方法调用顺序
【发布时间】:2016-11-25 00:44:45
【问题描述】:

考虑以下类层次结构:

class A {
    compute(int a) {
        compute(a, 1);
    }

    compute(int a, int b) {
        // do some things
    }
}


class B extends A {
    compute(int a, int b) {
        // do some stuff
    }
}

如果我使用 A 引用初始化 B 对象,如下所示:

A foo = new B();

如果我打电话:

foo.compute(1)

那么,在这个方法调用里面,会调用A类的compute(int, int)还是调用B类的compute(int, int)

官方 java 文档中的任何引用?

【问题讨论】:

标签: java oop


【解决方案1】:

我猜你是 C++ 程序员。当您没有将compute(int, int) 函数定义为virtual 时,您所指的行为确实会在C++ 中发生。

C++ 设计者一直在寻求极致性能,因此对象的非virtual 方法调用是在编译时定义的,以避免在其vtable 中额外引用函数指针,也就是它具有的虚函数。

如果是这样,让我告诉你,在 Java 中,所有方法在 C++ 术语中都隐式定义为 virtual。也就是说:对于给定的对象,任何被调用的方法总是属于被构造的对象,而不是属于引用它的变量。

【讨论】:

    【解决方案2】:

    我没有预先引用任何引文,但让我先解释一下会发生什么。

    我们有

    A foo = new B();

    这里 foo 的引用类型是A。被实例化的对象是B 类型。

    请注意,只有当对象 B 满足与 A 的 is-a 关系时,才能编译此语句。由于B extends AB 满足与A 的is-a 关系。

    foo 可以调用的方法基于引用类型。因此, foo 只能调用以A 类型声明/定义的方法。实际调用的方法基于对象类型。由于foo 引用的对象是B 类型,因此调用对象B 上的方法。因此,正在调用的是B.compute(int,int)

    【讨论】:

      【解决方案3】:

      调用的方法将是B.compute(int, int),您可以通过尝试轻松找到。


      既然您要求提供说明原因的文档,我将提供。但这并不容易。

      这在JLS Sec 15.12.4. Run-Time Evaluation of Method Invocation 中有描述。

      回想一下,有问题的方法调用是compute(a, 1);

      15.12.4.1。计算目标参考(如有必要)

      方法调用的形式是MethodName,并且是非静态的,所以适用以下情况:

      否则,令 T 为方法是其成员的封闭类型声明,令 n 为整数,使得 T 是其声明立即包含方法调用的类的第 n 个词法封闭类型声明。目标引用是 this 的第 n 个词法封闭实例。

      所以我们知道我们的目标参考。这是一种冗长的说法,我们将调用this 上的方法。

      15.12.4.2。评估参数

      这很简单,因为参数是ints。

      15.12.4.3。检查类型和方法的可访问性

      是的,类型和方法是可以访问的。

      15.12.4.4。定位调用方法

      调用方式为virtual,如Sec 15.12.3中所述。因此这适用:

      如果调用方式是接口或虚拟,则S最初是目标对象的实际运行时类R。

      请注意,如果您要在 compute(a, 1) 行之前立即写入 System.out.println(getClass()),则当以问题中所示的方式调用时,它将打印出 B,而不是 A。因此运行时类RB,所以S 也是B

      还有:

      令 X 为方法调用的目标引用的编译时类型。

      XA

      然后:

      类 S 包含一个名为 m 且具有相同描述符的方法的声明

      调用方式为virtualS中的声明覆盖X.m(§8.4.8.1),那么S中声明的方法就是要调用的方法,过程终止。

      所以,B 中声明的方法被调用了。


      这是相当繁重的阅读,老实说,你不需要知道这么多细节。这是我第一次真正费心去挑选规范的那部分内容。

      要记住的简单规则是:如果该方法在子类中被覆盖,那就是被调用的方法。

      【讨论】:

        猜你喜欢
        • 2013-11-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多