绑定和调度的关系是什么?它们是一样的吗?

时间:2018-03-23 14:18:59

标签: java oop

我已经看到一些资源,它声明动态调度和后期绑定是相同的。如果是,那么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

     

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

     

单一调度(动态):仅根据draw类型选择shape的实施,忽略{的类型或值{1}}。

     

多个调度(动态)boardshape的类型共同决定了将执行哪个board操作。 (在这种情况下,它是draw

我使用的资源很少:

1 个答案:

答案 0 :(得分:1)

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

绑定 dispatch 不同。

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

  • Dispatch (或更准确地说是 call dispatch method dispatch )是解决方法调用(或函数调用)的方法实现。使用静态调度早期绑定,可以在编译时通过动态调度 late绑定知道该调用的目标在运行时被选择。

    接口方法或虚拟方法(Java中的默认方法)使用动态调度。有效地静态分配了final方法,私有方法和静态方法(尽管严格来说,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调度)来实现,并且不需要复杂的逻辑。