我正在尝试在JAVA中创建双重调度以使用重载方法。
public abstract class ComposantOrdi {
protected void equiv(ComposantOrdi c){
Equivalence.equiv(this, c);
}
}
public class Montage extends ComposantOrdi{
protected void equiv(Montage montage){
Equivalence.equiv(this, montage);
}
}
public class Equivalence {
public static void equiv(Montage m, ComposantOrdi c){
System.out.println("Montage - ComposantOrdi");
}
public static void equiv(Montage m, Montage c){
System.out.println("Montage - Montage");
}
public static void equiv(ComposantOrdi m, ComposantOrdi c){
System.out.println("ComposantOrdi - ComposantOrdi");
}
}
对于示例,我创建了两个对象
Montage m2 = new Montage();
ComposantOrdi m3 = new Montage();
m3.equiv(m2);
m3.equiv(m3);
m3.equiv((Montage)m3);
结果是:
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
ComposantOrdi - ComposantOrdi
但我想使用Montage类的重载方法 得到这样的东西:
Montage - Montage
Montage - Montage
Montage - Montage
我可能不理解双重发送,但你能告诉我我做错了吗?
答案 0 :(得分:4)
您在代码中执行的操作是单个调度(不是双调度 - 下面的说明),因为在运行时只评估一个具体的子类型会影响结果(对象将自己传递为this
)。
此外,ComposantOrdi
和Montage
提供了不同的方法(检查参数:ComposantOrdi
获取ComposantOrdi
,而Montage
获取Montage
)。如果您调用超类“equiv
方法,则无法获得 Montage - Montage 等结果,因为每个传递的Montage
都会隐式投放到ComposantOrdi
。就像调用超类'方法一样,结果的第二部分不能是 ComposantOrdi 。
此外,如果您在
中调用超类'方法关键字this
Equivalence.equiv(this,c);
由超类触发,这意味着即使对象是Montage
,它也会将自身传递为ComposantOrdi
。
所以:调用超类'方法只能生成输出 ComposantOrdi - ComposantOrdi 。
对于像 Montage - Montage 这样的输出,您需要调用子类'方法equiv
,这意味着:
equiv
来电的接收方称为Montage
(请参阅主要内容中的m2
,而不是m3
)Montage
对象因为在this
中触发了关键字Montage
,所以输出的第一部分必须是 Montage 。第二部分也是 Montage ,因为如果不是必要的话,Java不会隐式地转换对象。这就是为什么选择带有Montages
作为参数的重载方法的原因。
所以:调用子类'方法只能生成输出蒙太奇 - 蒙太奇。
永远不会调用等价的equiv
方法的混合版本。
解释双重调度机制:
我认为双重调度机制存在根本性的误解。所以让我解释一下。在继续使用双重调度机制之前,我将开始解释单个调度。
单一调度: 单个调度意味着您调用对象的方法,并且执行的行为(方法调用的结果)取决于对象的具体类型。通常这称为多态,并使用抽象方法或方法覆盖来实现。
假设你有一个类系统,如下图所示。 Client
包含Shapes
列表。要绘制所有这些内容,它会遍历列表并在每个paint
上调用Shape
。当班级Triangle
在屏幕上绘制一个三角形时,Square
描绘一个正方形。通过不考虑Shapes
是哪个具体子类型,执行行为是在运行时确定的。
换句话说,paint方法调用的结果取决于Shape
接口的派生的具体子类型。 paint方法的调用是单个分派,因为只有一个具体子类型确定在运行时执行的行为。
DOUBLE DISPATCH:使用 double 分派机制,执行的行为在运行时受两个具体子类型的影响。像这样,你跨越一个动态评估的行为矩阵。
如果根据下图修改类系统,客户端触发的绘制机制依赖于两个对象 - Shape
和Painter
。客户端调用paint
方法并注入其Painter
。然后,Shape
将自己作为this
的一个重载方法中的Painter
传递。
像这样,Client
会触发绘制机制而不知道绘制什么颜色的形状。例如,如果其画家为GreenPainter
且Shape
为Triangle
,则屏幕上会显示绿色三角形。
在此示例中,双调度机制由Shapes
'paint
方法的调用触发。
您应该查看使用双重调度机制的访客模式。
答案 1 :(得分:1)
一般JVM只使用单一调度:运行时类型仅考虑接收者对象;对于方法的参数,考虑静态类型。
如果您希望多次调度参数,并希望坚持使用Java,请查看MultiJava
如果您的目标是坚持普通的,普通的java,请阅读其他设计模式,例如,策略,访客,观察者。这些通常可以解决与多次调度相同的问题