我确实知道覆盖和重载之间的语法差异。而且我也知道覆盖是运行时多态性,而重载是编译时多态性。但我的问题是:“重载真的是编译时多态性吗?方法调用真的在编译时解决吗?”。为了澄清我的观点,让我们考虑一个示例类。
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
的对象,或其任何子类,如 FancyGreeter
或 GraphicalGreeter
或任何其他对象。 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/