重载是编译时多态性.真的吗?
我确实知道覆盖和重载之间的语法差异.而且我也知道覆盖是运行时多态性,而重载是编译时多态性.但我的问题是:重载真的是编译时多态性吗?方法调用真的在编译时解决吗?".为了澄清我的观点,让我们考虑一个示例类.
I do know the syntactical difference between overriding and overloading. And I also know that overriding is run-time polymorphism and overloading is compile-time polymorphism. But my question is: "Is overloading is really compile-time polymorphism? Is the method call really solving at compile time?". To clarify my point, let's consider an example class.
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()
都是公共的,它们都可以被覆盖(包括重载的),对吧?例如,
Since all of the methods greetMe(), greetMe(String name), wishLuck()
are public, they all can be overriden(including overloaded one), right? For example,
public class FancyGreeter extends Greeter {
public void greetMe() {
System.out.println("***********");
System.out.println("* Hello *");
System.out.println("***********");
}
}
现在,考虑以下代码段:
Now, consider the following snippet:
Greeter greeter = GreeterFactory.getRandomGreeter();
greeter.greetMe();
getRandomGreeter()
方法返回一个随机的Greeter
对象.它可以返回 Greeter
的对象,或其任何子类,如 FancyGreeter
或 GraphicalGreeter
或任何其他对象.getRandomGreeter()
将使用 new
创建对象或动态加载类文件并使用反射创建对象(我认为可以使用反射)或任何其他方式是可能的.Greeter
的所有这些方法可能会或可能不会在子类中被覆盖.所以编译器无法知道某个特定的方法(重载与否)是否被覆盖.对?此外,维基百科在 虚拟函数上说:
The getRandomGreeter()
method returns a random Greeter
object. It may either return an object of Greeter
, or any of its subclasses, like FancyGreeter
or GraphicalGreeter
or any other one. The getRandomGreeter()
will create the objects either using new
or dynamically load the class file and create object using reflection(I think it is possible with reflection) or any other way that is possible. All of these methods of Greeter
may or may not be overriden in subclasses. So the compiler has no way to know whether a particular method(overloaded or not) is overriden. Right? Also, wikipedia says on Virtual functions:
在 Java 中,所有非静态方法默认都是虚拟函数".只有用关键字final标记的方法,不能被覆盖,以及不被继承的私有方法都是非虚拟的.
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.
由于虚函数是在运行时使用动态方法分派解决的,并且由于所有非私有、非最终方法都是虚拟的(无论是否重载),它们必须在运行时解决.对吧?
Since, virtual functions are resolved at run-time using dynamic method dispatch, and since all non private, non final methods are virtual(whether overloaded or not), they must be resolved at run-time. Right?
那么,如何在编译时解决重载问题?或者,有什么我误解了,或者我遗漏了什么?
Then, How can overloading still be resolved at compile-time? Or, is there anything that I misunderstood, or am I missing?
推荐答案
重载的方法仍然可以被覆盖,如果这是你的要求.
Overloaded methods can still be overridden, if that is what you ask.
重载方法就像不同的系列,尽管它们共享相同的名称.编译器静态选择一个给定签名的族,然后在运行时将其分派到类层次结构中最具体的方法.
Overloaded methods are like different families, even though they share the same name. The compiler statically chooses one family given the signature, and then at run time it is dispatched to the most specific method in the class hierarchy.
即方法分派分两步进行:
That is, method dispatching is performed in two steps:
- 第一个是在编译时使用可用的静态信息完成的,编译器将为在声明类型的重载方法列表中与当前方法参数最匹配的签名发出
call
调用该方法的对象的名称. - 第二步在运行时执行,给定应该调用的方法签名(上一步,还记得吗?),JVM 会将其分派到接收器对象的实际类型中最具体的覆盖版本.
- The first one is done at compile time with the static information available, the compiler will emit a
call
for the signature that matches best your current method parameters among the list of overloaded methods in the declared type of the object the method is invoked upon. - The second step is performed at run time, given the method signature that should be called (previous step, remember?), the JVM will dispatch it to the most concrete overridden version in the actual type of receiver object.
如果方法参数类型根本不是协变的,则重载相当于在编译时修改方法名称;因为它们实际上是不同的方法,所以 JVM 永远不会根据接收器的类型互换地分派它们.
If the method arguments types are not covariant at all, overloading is equivalent to having methods names mangled at compile time; because they are effectively different methods, the JVM won't never ever dispatch them interchangeably depending on the type of the receiver.
相关文章