【问题标题】:Why is an infinite loop not caused by Java double dispatch?为什么Java双重调度不会导致无限循环?
【发布时间】:2017-02-27 14:58:58
【问题描述】:

在讲座中,我们看到了这段代码,并告诉我们它会创建双重调度,但为什么它没有创建无限循环?

如果 c3po.greet(c4po);从 TranslationRobot 调用 TranslationRobot 方法

为什么 c5po.greet(c4po);调用 CarrierRobot 中的 AbstractRobot 方法而不是 TranslationRobot 方法,然后不调用 TranslationRobot 中的 AbstractRobot 方法,然后调用 CarrierRobot 中的 Abstract 方法等等?

什么决定了它是否调用 AbstractRobot 方法?

AbstractRobot.java

abstract class AbstractRobot extends Robot { 
abstract void greet(AbstractRobot other);
abstract void greet(TranslationRobot other);
abstract void greet(CarrierRobot other);
}

CarrierRobot.Java

class CarrierRobot extends AbstractRobot {
...
void greet(TranslationRobot other) {
    talk("'Hello from a TranslationRobot to a CarrierRobot.'"); }
void greet(CarrierRobot other) {
    talk("'Hello from a CarrierRobot to another.'"); }
void greet(AbstractRobot other) {
    other.greet(this); 
}}

TranslationRobot.Java

public class TranslationRobot extends AbstractRobot {
...
void greet(TranslationRobot other) {
    talk("'Hello from a TranslationRobot to another.'"); }
void greet(CarrierRobot other) {
    talk("'Hello from a CarrierRobot to a TranslationRobot.'"); }
void greet(AbstractRobot other) {
    other.greet(this);
} } 

DispatchWorld.Java

class DispatchWorld {
public static void main (String[] args) {
AbstractRobot c3po = new TranslationRobot();
AbstractRobot c4po = new TranslationRobot();
AbstractRobot c5po = new CarrierRobot();
AbstractRobot c6po = new CarrierRobot();
c3po.greet(c4po);
c5po.greet(c4po);
c4po.greet(c5po);
c5po.greet(c6po);
} }

这会产生输出:

Standard Model says 'Hello from a TranslationRobot to another.'
Standard Model says 'Hello from a CarrierRobot to a TranslationRobot.'
Standard Model says 'Hello from a TranslationRobot to a CarrierRobot.'
Standard Model says 'Hello from a CarrierRobot to another.'

【问题讨论】:

  • 方法名的重载选择是在编译时根据方法参数的static类型进行的。在 Java 中实现双重分派时,这可能是最重要的一点。
  • 我不同意这是一个重复的问题,另一个有一个父类,从该类中调用该方法并询问为什么“this”指的是父类而不是子类。而在这里我要问的是为什么在同一个类中选择一种方法而不是另一种方法,以及为什么论点是抽象的或具体的
  • 虽然欺骗目标在某些细节上有所不同,但本质上是同一个问题:双重调度中特定的重载方法如何绑定到方法调用?接受的对欺骗目标的回答很好地解决了这个问题,既回答了那个版本的问题,也回答了这个问题。
  • 运行的方法是您调用其方法的对象的运行时类型中的方法。 c3po.greet 是来自 TranslationRobot 的方法,因为那是对象的类型。 ` c5po.greet(c4po);` 不“调用 CarrierRobot 中的 AbstractRobot 方法”,它调用 CarrierRobot#greet。因为那是对象的类型。它将如何从TranslationRobot 调用方法?这不是对象的类型,也不是其变量的类型。那么,你所描述的这种循环怎么会出现呢?

标签: java double-dispatch


【解决方案1】:

我认为,如果我们通过删除所有方法重载并改用显式不同的名称来稍微重构代码,则可以更好地说明为什么这样做以及为什么没有无限递归的答案:

abstract class Robot
{
    void talk(String msg)
    {
        System.out.println(msg);
    }
}

abstract class AbstractRobot extends Robot
{
    abstract void greet(AbstractRobot other);

    abstract void greetFromTranslationRobot(TranslationRobot other);

    abstract void greetFromCarrierRobot(CarrierRobot other);
}

class CarrierRobot extends AbstractRobot
{
    void greetFromTranslationRobot(TranslationRobot other)
    {
        talk("'Hello from a TranslationRobot to a CarrierRobot.'");
    }

    void greetFromCarrierRobot(CarrierRobot other)
    {
        talk("'Hello from a CarrierRobot to another.'");
    }

    void greet(AbstractRobot other)
    {
        other.greetFromCarrierRobot(this);
    }
}


public class TranslationRobot extends AbstractRobot
{
    void greetFromTranslationRobot(TranslationRobot other)
    {
        talk("'Hello from a TranslationRobot to another.'");
    }

    void greetFromCarrierRobot(CarrierRobot other)
    {
        talk("'Hello from a CarrierRobot to a TranslationRobot.'");
    }

    void greet(AbstractRobot other)
    {
        other.greetFromTranslationRobot(this);
    }
}

从编译器的角度来看,void greet(AbstractRobot other)void greet(TranslationRobot other)void greet(CarrierRobot other) 是三种明显不同的方法,我的重命名只是强调了这些方法。

所以像c3po.greet(c4po) 这样的调用实际上是对TranslationRobot.greet 的调用,它会将其转发给other.greetFromTranslationRobot(this),即TranslationRobot.greetFromTranslationRobot,显然不应导致任何无限递归。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 2016-11-11
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 2017-09-08
    • 1970-01-01
    相关资源
    最近更新 更多