java - 为什么方法重载决策是在编译时确定的?

标签 java virtual-functions dynamic-dispatch

我试图理解为什么我们有重写方法的多态性/动态绑定(bind),但没有重载方法。我知道有一种间接方法可以让我们索引到 vtable,从而允许我们用 C++ 或 Java 等语言来执行此操作。我很好奇为什么解析重载方法的情况并非如此——我的直觉让我相信我们可以有一定程度的间接性,允许我们在运行时根据运行时类型确定要调用哪个重载方法。

我想知道这个设计决策是否是出于性能原因,或者是否存在我忽略考虑的额外复杂性。

最佳答案

我没有读懂语言设计者的想法,所以不能真正告诉你。我是这样想的:

  • 重写方法是同一方法在父类(super class)/子类层次结构中不同级别的不同实现。子类一般使用相同的方法签名(允许返回更具体的类型并声明更少的抛出异常,但不能完全重新定义方法头,否则将不再是重写)。
  • 重载方法实际上只是碰巧具有相同名称的不同方法。然后通过参数类型来区分。就像编译器总是在编译时决定调用哪个方法一样,重载方法也是如此。

作为一项观察(可能是次要观察),通过重载方法的运行时解析,我们无法再对返回值进行静态类型检查。想象一下我们有

public boolean foo(Number n);
public String foo(Integer i);

现在我发现像这样调用前一个 foo() 是非常自然的:

    boolean result = foo(myNumber);

现在,如果 myNumber 碰巧是一个 Integer,则将调用后者的 foo()。它将返回一个 String 并且我会在运行时发生类型转换错误。我不会感到惊讶。

… why then we can still have runtime polymorphism and it be considered static typing, but it wouldn't be if we did dynamic resolution of overloaded methods.

Java 同时具有:静态类型和运行时类型。当我将 Integer 存储到声明为 Number 的变量中时,Number 是静态类型,而 Integer是运行时类型(顺便说一句,类型与类不同)。你是对的,当我执行 myObject.foo(arg) 时,myObject 的运行时类型决定了 foo() 的实现叫。可以想象,arg 的运行时类型也可能参与决策。事情会变得更加复杂,而且我不确定 yield 如何。

关于java - 为什么方法重载决策是在编译时确定的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64888087/

相关文章:

swift - Swift 中的动态调度和协议(protocol)

java - 重写方法中的方法参数注释

java - 为什么 Maven 每次都下载 maven-metadata.xml?

java - 在java中的实体类中设置变量值(硬代码)的最佳实践

C++ 调试 "smell"

c++ - 在派生类中强制执行正确的虚函数定义

c++ - 为什么派生类没有vtable指针而是使用基类的vtable?

java.lang.StringIndexOutOfBoundsException : while using charAt function

java - 这个升级演示如何运作?