什么是动态方法分派,它与继承有什么关系?

12
什么是Java中的“动态分派”,在继承的语境下为什么需要它?
3个回答

14

Java中的动态分派是什么意思?

将"分派"视为"确定要调用的方法"。

"动态"部分只是表示它在运行时确定。也就是说,要调用哪个方法是在运行时确定的。

在继承的情况下为什么需要它?

如果没有继承/多态性,我们就不需要这个。表达式的类型将在编译时可确定,并且编译程序时会知道将要调用哪个方法。

使用继承/多态性,我们不知道表达式的具体运行时类型,因此必须在运行时 "动态" 确定要调用的方法。

没有动态分派,虚方法就没有意义了,而这对于抽象和封装至关重要。

推荐阅读: Wikipedia article on Dynamic Dispatch


请问您能否分享一些示例来解释这个观点:“通过继承/多态,我们无法知道表达式的具体运行时类型,因此在运行时必须“动态”确定要调用的方法。” - prime
2
很简单:如果你不能使用 List<String> l = new ArrayList<>();,而必须使用 ArrayList<String> l = new ArrayList<>();,那么你就不需要动态分派,因为在运行时 l 的类型必然是 ArrayList(它不能是任何其他的 List)。这将使得动态分派变得无意义,因为编译器可以直接将对 l.add(...) 的调用硬编码到 ArrayList.add 方法(而不是将其分派到 ArrayList.addLinkedList.add)。 - aioobe
1
单分派:你基于单个输入(例如对象类型)来选择方法。多分派:你基于多个输入(例如对象类型和参数类型)来选择方法。在Java中,你可以根据提供的不同类型的参数调用不同的方法(即方法重载),但这种机制完全运行在编译时。因此,对于多分派,想象一下这是在运行时决定的:Object o =“hello”;m(o)Object o = new Integer(5); m(o) 可以调用不同的方法。 - aioobe
不能确定,但可能的解释是:效率。简单性。与C++中虚方法相同的语义。 - aioobe
嗯,无论如何我都提出了一个问题。如果您有时间,请看一下并提供一些想法 :) 感谢您的支持。 - prime
显示剩余4条评论

13

其他回答讨论了理论,这里提供一个示例来展示为什么需要动态分派(也称为后期绑定)。

假设你有一个名为'Rectangle'的类。

public class Rectangle{
  public void draw() {
     System.out.println("___\n| |\n---");
     //does it look nice?
  }
}

并且您有一个带圆角的子类

public class RoundedRectangle extends Rectangle {
  @Override
  public void draw() {
     System.out.println("assume it is a rectangle with rounded corners");
  }
}

现在假设你有一个带有Rectangle类型参数的获取方法,该方法用于调用绘图方法。

public class Demo() {
...
  public demonstration(Rectangle rect) {
    rect.draw();
  }
...
}
如果这个方法的参数是Rectangle类的话,它将会绘制。
___
| |
---

但当参数类型为RoundedRectangle时,我们期望:

assume it is a rectangle with rounded corners
这就是晚期绑定所必需的地方:当代码编译时,不清楚哪个方法需要被调用 rect.draw(); 可能是Rectangle.draw(),也可能是RoundedRectangle.draw(),或者是尚未实现的任何其他子类的draw方法。
摘要(从开发者的角度来看):
因此,晚期绑定意味着:针对一个只知道它属于一个特定类或子类的实例,调用具有给定签名(方法名和参数列表)的方法 - 但不知道确切的类是什么。当方法被覆盖时,调用覆盖方法。
因此,多态性与晚期绑定并不矛盾--当您拥有多态性时,就需要晚期绑定。在Java和C++中(我相信,在任何其他面向对象的语言中也是如此)。

@Ralph 这个回答非常好!!!您能否举例说明一下“单分派”和“双/多分派”的概念呢? - prime

1
Java中的动态方法调度是什么?
与其他语言一样。根据调用方法的对象类型选择动态分派到一个方法。
为什么在继承的情况下需要DMD(动态方法调度)?
只有在这种情况下才需要它。如果没有继承,就没有什么可以动态处理的了。
C++中的多态和Java中的DMD哪个更好?
这个问题是没有意义的,因为它们并不不同。DMD是实现多态的一种机制。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接