什么是Java中的“动态分派”,在继承的语境下为什么需要它?
Java中的动态分派是什么意思?
将"分派"视为"确定要调用的方法"。
"动态"部分只是表示它在运行时确定。也就是说,要调用哪个方法是在运行时确定的。
在继承的情况下为什么需要它?
如果没有继承/多态性,我们就不需要这个。表达式的类型将在编译时可确定,并且编译程序时会知道将要调用哪个方法。
使用继承/多态性,我们不知道表达式的具体运行时类型,因此必须在运行时 "动态" 确定要调用的方法。
没有动态分派,虚方法就没有意义了,而这对于抽象和封装至关重要。
其他回答讨论了理论,这里提供一个示例来展示为什么需要动态分派(也称为后期绑定)。
假设你有一个名为'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方法。
List<String> l = new ArrayList<>();
,而必须使用ArrayList<String> l = new ArrayList<>();
,那么你就不需要动态分派,因为在运行时l
的类型必然是ArrayList
(它不能是任何其他的List
)。这将使得动态分派变得无意义,因为编译器可以直接将对l.add(...)
的调用硬编码到ArrayList.add
方法(而不是将其分派到ArrayList.add
或LinkedList.add
)。 - aioobeObject o =“hello”;m(o)
和Object o = new Integer(5); m(o)
可以调用不同的方法。 - aioobe