重载是编译时多态性。真的吗?
我确实知道重写和重载之间的语法差异。我还知道重写是运行时多态性,重载是编译时多态性。但我的问题是:“重载真的是编译时多态性吗?方法调用真的是在编译时解决的吗?”。为了阐明我的观点,让我们考虑一个示例类。
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 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
的所有这些方法可能会也可能不会在子类中被重写。因此编译器无法知道特定方法(是否重载)是否被重写。正确的?另外,维基百科关于虚拟函数的说法:
在Java中,所有非静态方法默认都是“虚函数”。 仅限使用关键字final标记的方法,该方法不能被覆盖, 与不可继承的私有方法一样,它们都是非虚拟的。
由于虚拟函数是在运行时使用动态方法分派来解析的,并且由于所有非私有、非最终方法都是虚拟的(无论是否重载),因此它们必须在运行时解析。正确的?
那么,如何才能在编译时解决重载呢?或者,我是否误解了什么,或者我错过了什么?
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");
}
}
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();
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:
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
每个“Greeter”类都有 3 个虚拟方法:
voidgreetMe()
、voidgreetMe(String)
和voidwishLuck()
。当您调用greeter.greetMe()时,编译器可以根据方法签名计算出应该调用三个虚拟方法中的哪一个 - 即。
voidgreetMe()
,因为它不接受任何参数。调用voidgreetMe()
方法的具体实现取决于greeter
实例的类型,并在运行时解析。在您的示例中,编译器确定要调用哪个方法很简单,因为方法签名完全不同。显示“编译时多态性”概念的一个稍微更好的示例可能如下:
使用此greeter类将给出以下结果:
编译器将使用编译时类型挑选出最具体匹配的方法,这就是为什么第二个示例有效并调用
voidgreetMe(String)
方法。最后一个调用是最有趣的一个:尽管 strAsObj 的运行时类型是
String
,但它已被转换为Object
,因此编译器是这样看待它的。因此,编译器可以为该调用找到的最接近的匹配是voidgreetMe(Object)
方法。Every 'Greeter' class has 3 virtual methods:
void greetMe()
,void greetMe(String)
, andvoid wishLuck()
.When you call
greeter.greetMe()
the compiler can work out which one of the three virtual methods should be called from the method signature - ie. thevoid greetMe()
one since it accepts no arguments. Which specific implementation of thevoid greetMe()
method is called depends on the type of thegreeter
instance, and is resolved at run-time.In your example it's trivial for the compiler to work out which method to call, since the method signatures are all completely different. A slightly better example for showing the 'compile time polymorphism' concept might be as follows:
Using this greeter class will give the following results:
The compiler will pick out the method with the most specific match using the compile-time type, which is why the 2nd example works and calls the
void greetMe(String)
method.The last call is the most interesting one: Even though the run-time type of strAsObj is
String
, it has been cast as anObject
so that's how the compiler sees it. So, the closest match the compiler can find for that call is thevoid greetMe(Object)
method.如果您要求的话,重载方法仍然可以被重写。
重载方法就像不同的家族,尽管它们共享相同的名称。编译器在给定签名的情况下静态选择一个系列,然后在运行时将其分派到类层次结构中最具体的方法。
也就是说,方法分派分两步执行:
调用
,以获取与当前方法参数最匹配的签名。调用该方法的对象的声明类型中的重载方法列表。如果方法参数类型根本不协变,则重载相当于在编译时破坏方法名称;因为它们实际上是不同的方法,所以 JVM 永远不会根据接收器的类型互换地分派它们。
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
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.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.
什么是多态性?
根据。对我来说:如果一个实体可以用多种形式表示,则该实体被称为表现出多态性。
现在,让我们将此定义应用于 Java 构造:
1) 运算符重载是编译时多态性。
例如,
+
运算符可用于将两个数字相加或连接两个字符串。这是多态性的一个例子,严格来说是编译时多态性。2)方法重载是编译时多态性。
例如,同名的方法可以有多个实现。它也是一种编译时多态性。
它是编译时的,因为在程序执行之前,编译器决定程序的流程,即在运行时使用哪种形式。
3)方法重写是运行时多态性。
例如,具有相同签名的方法可以有多个实现。这是运行时多态性。
4) 使用基类代替派生类是运行时多态性。
例如,
接口
引用可以指向它的任何实现者。它是运行时的,因为程序的流程在执行之前无法得知,即只有在运行时才能决定使用哪种形式。
我希望它能澄清一点。
What is polymorphism?
Acc. to me: if an entity can be represented in more than one forms, that entity is said to exhibit polymorphism.
Now, lets apply this definition to Java constructs:
1) Operator overloading is compile time polymorphism.
For example,
+
operator can be used to add two numbers OR to concatenate two strings. it's an example of polymorphism strictly saying compile-time polymorphism.2) Method overloading is compile time polymorphism.
For example, a method with same name can have more than one implemntations. it's also a compile-time polymorphism.
It's compile-time because before execution of program compiler decides the flow of program i.e which form will be used during run-time.
3) Method overriding is run-time polymorphism.
For example, a method with same signature can have more than one implemenations. it's a run time polymorphism.
4) Base class use in place of derived class is run time polymorphism.
For example, an
interface
reference can point to any of it's implementor.It's run-time because the flow of program can't be known before execution i.e. only during run-time it can be decided that which form will be used.
I hope it clears a bit.
在这方面,重载意味着函数的类型是在编译时静态确定的,而不是动态分派。
幕后真正发生的事情是,对于类型为“A”和“B”的名为“foo”的方法,创建了两个方法(“foo_A”和“foo_B”)。其中要调用的对象是在编译时确定的(
foo((A) object)
或foo((B) object)
结果为foo_A< /code> 被调用或
foo_B
)。因此,在某种程度上,这是编译时多态性,尽管真正的方法(即采用类层次结构中的哪个实现)是在运行时确定的。Overloading in this respect means that the type of the function is statically determined at compile time as opposed to dynamic dispatch.
What really happens behind the scenes is that for a method named "foo" with types "A" and "B" two methods are created ("foo_A" and "foo_B"). Which of them is to be called is determined at compile-time (
foo((A) object)
orfoo((B) object)
result infoo_A
being called orfoo_B
). So in a way this is compile-time polymorphism, although the real method (i.e. which implementation in the class hierarchy to take) is determined at runtime.我强烈反对将方法重载称为编译时多态性。
我同意方法重载是静态绑定(编译时),但我没有看到其中的多态性。
我试图在我的问题中提出我的意见以获得澄清。您可以参考此链接。
I have strong objection to call method overloading as compile time polymorphism.
I agree that method overloading is static binding(compile time) but i didn't see polymorphism in that.
I tried to put my opinion in my question to get clarification. you can refer this link.