java - 重载是编译时多态性。真的吗?

标签 java polymorphism overloading overriding method-dispatch

我确实知道覆盖和重载之间的语法差异。而且我也知道覆盖是运行时多态性,而重载是编译时多态性。但我的问题是:“重载真的是编译时多态性吗?方法调用真的在编译时解决吗?”。为了澄清我的观点,让我们考虑一个示例类。

public class Greeter {
    public void greetMe() {
        System.out.println("Hello");
    }

    public void greetMe(String name) {
        System.out.println("Hello " + name);
    }

    public void wishLuck() {
        System.out.println("Good Luck");
    }
}

由于所有方法 greetMe(), greetMe(String name), wishLuck() 都是公共(public)的,它们都可以被覆盖(包括重载的),对吧?例如,

public class FancyGreeter extends Greeter {
    public void greetMe() {
        System.out.println("***********");
        System.out.println("*  Hello  *");
        System.out.println("***********");
    }
}

现在,考虑以下代码段:

Greeter greeter = GreeterFactory.getRandomGreeter();
greeter.greetMe();

getRandomGreeter() 方法返回一个随机的Greeter 对象。它可以返回 Greeter 的对象,或其任何子类,如 FancyGreeterGraphicalGreeter 或任何其他对象。 getRandomGreeter() 将使用 new 创建对象或动态加载类文件并使用反射创建对象(我认为可以使用反射)或任何其他方式是可能的。 Greeter 的所有这些方法可能会或可能不会在子类中被覆盖。所以编译器无法知道某个特定的方法(重载与否)是否被覆盖。正确的?此外,维基百科在 Virtual functions 上说:

In Java, all non-static methods are by default "virtual functions". Only methods marked with the keyword final, which cannot be overridden, along with private methods, which are not inherited, are non-virtual.

由于虚函数是在运行时使用动态方法分派(dispatch)解决的,并且由于所有非私有(private)、非 final方法都是虚拟的(无论是否重载),它们必须在运行时解决。对吧?

那么,如何在编译时解决重载问题?或者,有什么我误解了,或者我遗漏了什么?

最佳答案

每个 'Greeter' 类都有 3 个虚拟方法:void greetMe()void greetMe(String)void wishLuck() .

当您调用 greeter.greetMe() 时,编译器可以确定应该从方法签名中调用三个虚拟方法中的哪一个 - 即。 void greetMe() 之一,因为它不接受任何参数。调用 void greetMe() 方法的具体实现取决于 greeter 实例的类型,并在运行时解析。

在您的示例中,编译器很容易确定调用哪个方法,因为方法签名完全不同。显示“编译时多态性”概念的一个稍微好一点的例子可能如下:

class Greeter {
    public void greetMe(Object obj) {
        System.out.println("Hello Object!");
    }

    public void greetMe(String str) {
        System.out.println("Hello String!");
    }
}

使用这个greeter类会得到以下结果:

Object obj = new Object();
String str = "blah";
Object strAsObj = str;

greeter.greetMe(obj); // prints "Hello Object!"
greeter.greetMe(str); // prints "Hello String!"
greeter.greetMe(strAsObj); // prints "Hello Object!"

编译器将使用编译时类型挑选出最具体匹配的方法,这就是第二个示例有效并调用 void greetMe(String) 方法的原因。

最后一个调用是最有趣的:尽管 strAsObj 的运行时类型是 String,但它已被转换为 Object,所以编译器就是这样处理的看到它。因此,编译器可以为该调用找到最接近的匹配是 void greetMe(Object) 方法。

关于java - 重载是编译时多态性。真的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8355912/

相关文章:

java - Spring 数据 : default 'not deleted' logic for automatic method-based queries when using soft-delete policy

java.net.URLDecoder 依赖源文件编码?

c++ - 如何让一个接口(interface)返回不同的数据类型?

c++ - C++ 和 Objective C 中的多态性

matlab - Matlab中的继承多态性

c++ - 使用模板特化和接口(interface)对实例和原始类型进行统一函数调用

c++ - 你为什么要将 operator `new` 设为私有(private)?

java - 复合键未由相应的 ID 填充

c++ - 函数重载,无法推导出模板参数

java - 在 Hibernate 中创建查询