【问题标题】:What is the relationship of binding and dispatching ? Are they the same?绑定和调度是什么关系?它们是一样的吗?
【发布时间】:2018-03-23 14:18:58
【问题描述】:

我看到一些资源表明动态调度和后期绑定是相同的。如果是这样,那么binding 应该等于dispatching。在某些地方,他们声明overloading/early binding/ static dispatch 相同,overriding/late binding/ dynamic dispatch 相同。

所以我想出了一个比喻来理解这一点。 下面的比喻正确吗?或者我该如何修改下面的解释。

我们的类结构如下。

class Board {
    public void show(){};
}

class Shape{
    public void draw(Board board) {};
}

class Square extends Shape {
    public void draw(Board board) {
        System.out.println("Drawing a Square");
    };
}

class Circle extends Shape {
    public void draw(Board board) {
        System.out.println("Drawing a Circle");
    };
}

我们有:

Shape shape = createShape(type); // This will return any of Shape, Square, Circle
shape.draw(board);

我们有:

Board myBoard = new Board();
myBoard.show();

我想出了一些解释,

绑定:确定shape 的实际类型(可以是Shape、Square 或Circle)。假设shape 的类型仅在运行时已知,则为late binding。可以在编译时确定myBoard 的类型。这是early binding

调度:决定draw 的实际实现被认为是dispatching。如果draw 的实际实现只能在运行时确定,则为dynamic dispatching,否则如果可以在编译时确定,则称为static dispatching

Static Dispatch :当我在编译时知道调用方法时将执行哪个函数体时发生。所以myBoard.show(),这里方法show可以静态调度。其中shape.draw(board) 我们不能静态调度draw,因为我们不能保证在运行时会执行哪个函数体。

单一调度(动态):将仅根据 shape 的类型选择 draw 的实现,而不考虑 board 的类型或值。

多次调度(动态)shapeboard 的类型共同决定了将执行哪个draw 操作。 (在这种情况下是Double Dispatch

我使用的资源很少:

【问题讨论】:

  • "如果是这样,那么binding 应该等于dispatching。" - 我不会这么说。 “绑定”是指将标识符与方法相关联。 “调度”是指进行实际调用。但是,如果您“绑定较晚”,则调度到静态决定的方法是没有意义的。如果你“早绑定”你别无选择,你必须在编译时选择一个方法。
  • 那么后期绑定实际上是动态调度吗?对于上述解释,你能说什么,那么解释是否正确?
  • 当然,后期绑定可以看作是动态调度的同义词。 (你真的不能没有另一个。)回复。 绑定:不是shape 的实际类型,根据shape 的类型,Java 碰巧调用哪个方法调度:LGTM。 静态调度:嗯,Board.show 可以被覆盖。如果该方法是静态的,或者 Board 和/或 Board.show 是最终的,我会同意。 Single Dispatch/Multiple Dispatch:嗯,可以是参数类型,在技术上也可以是其他属性,例如 shape 的类型 + 月相。
  • 所以基本上它是静态调度方法应该是非虚拟的?
  • @aioobe 所以单个和多个解释是正确的,但也可以有其他场景和组合,这就是你的意思我猜。

标签: java oop


【解决方案1】:

最后给这个问题一个答案:

Bindingdispatch不一样。

  • 绑定通常是指将符号解析为某个值/对象/实现。例如,赋值语句x = 42 将符号x 绑定到表达式42 的值。在 Java 中,类型名称始终可以在编译期间解析。

  • Dispatch(或更准确地说是call dispatchmethod dispatch)是一种解决方法调用(或函数调用)的绑定到方法实现。 static dispatchearly binding 调用的目标可以在编译时知道,使用 dynamic dispatchlate binding em> 方法调用的目标是在运行时选择的。

    接口方法或虚拟方法(Java 中的默认方法)使用动态调度。最终方法、私有方法和静态方法被有效地静态调度(虽然严格来说,JVM 仍然必须解析调用)。

我还会很快提到,表达式的静态类型是表达式的静态已知或“声明”类型,而动态类型是该表达式的运行时值的实际类型。例如。当我们声明一个变量 Board b 时,b 的静态类型是 Board 类,但动态类型可能是 Board 或其任何子类——我们不知道,直到它被分配一个特定的对象.一旦知道动态类型,就可以绑定动态分派的方法(假设 Java 中基于类型的单一分派)。

您的myBoard.show() 示例使用虚拟方法并且通常会被动态分派:myBoard 被声明为具有Board 类型或任何Board 子类。如果您将类或 show() 声明为 final,这将会改变。在实践中,这个特定示例可以优化为静态调度,因为您在同一范围内构造new Board(),因此myBoard 的动态类型是已知的。但这只是一种优化。

相比之下,您的createShape().draw() 示例显然是动态调度,因为调用者不知道createShape() 的动态类型。

您对单调度/多调度的理解基本上是正确的。

我想指出,解决函数调用的一般意义上的“分派”不一定限于类型。我们还可以使用 if/elses 中的逻辑来调度调用。考虑这个例子,我们根据 x 和 y 的值将quadrant(x,y) 调用发送到特定象限,例如东北象限。从语言的角度来看,这是静态调度,但从程序员的角度来看,它的行为更像是静态调度。

class Quadrants {
  ...
  public static void quadrant(int x, int y, String value) {
    // dispatch a call with a x→east, y→north coordinate system
    if (x >= 0) {
      if (y >= 0) {
        quadrantNE(value);
      } else {
        quadrantSE(value);
      }
    } else {
      if (y >= 0) {
        quadrantNW(value);
      } else {
        quadrantSW(value);
      }
    }
  }
  private static void quadrantNE(String value) { ... }
  private static void quadrantNW(String value) { ... }
  private static void quadrantSE(String value) { ... }
  private static void quadrantSW(String value) { ... }
}

在底层,语言运行时也会使用一些逻辑来执行动态调度,尤其是对于多调度。基于类型的单一调度(如静态类型为类的 Java 中的实例方法调用)可以通过简单的表查找(vtable 调度)来实现,不需要复杂的逻辑。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    • 2014-03-06
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多