【问题标题】:What is the difference between Binding and Dispatching in Java?Java中的绑定和调度有什么区别?
【发布时间】:2017-05-22 07:47:31
【问题描述】:

关联的名字太多了:Early and Late Binding、Static and Dynamic Dispatch、Runtime vs. Compile-time Polymorphism等等,我不明白其中的区别。

我找到了一个明确的explanation,但它是正确的吗?我将解释 JustinC

绑定:是确定变量(对象?)的类型。如果它是在编译时完成的,它的早期绑定。如果它是在运行时完成的,那就是后期绑定。

Dispatch: 正在确定与方法调用匹配的方法。静态分派是在编译时计算方法,而动态分派是在运行时进行。

绑定是否将原始变量和引用变量分别与原始值和对象匹配?

编辑:请给我一些清晰的参考资料,以便我阅读更多相关信息。

【问题讨论】:

标签: java late-binding dynamic-dispatch early-binding static-dispatch


【解决方案1】:

我认为混淆通常来自这些术语的过载程度。

我们用高级语言编写程序,编译器或解释器必须将其转换为机器真正理解的东西。

粗略地说,您可以想象编译器将我们的方法代码转换为某种形式的机器代码。如果编译器在我们稍后运行程序时知道该方法在内存中的确切位置,那么它可以安全地找到该编译方法的每个方法调用,并将其替换为跳转到编译代码所在的地址居住,对吧?

嗯,实现这种关系就是我理解的约束。但是,这种绑定可能发生在不同的时刻,例如在编译时、链接时、加载时或运行时,具体取决于语言的设计。

术语静态和动态通常分别用于指代在运行时和运行时绑定的事物。

较晚的绑定时间与更大的灵活性相关联,较早的绑定时间与更高的效率相关联。语言设计师在创建语言时必须平衡这两个方面。

大多数面向对象的编程语言都支持子类型多态。在这些语言中,虚拟方法在运行时绑定,具体取决于该点对象的动态类型。换句话说,虚拟方法调用在运行时根据所涉及的对象实现的动态类型而不是仅基于其静态类型引用被分派到适当的实现。

所以,在我看来,你必须先将方法调用绑定到特定的实现或执行地址,然后才能向它分派调用。

我在过去had answered 提出了一个非常相似的问题,我通过示例演示了 Java 中这是如何发生的。

我还建议阅读本书Programming Language Pragmatics。从理论的角度学习所有这些东西是一个很好的参考。

【讨论】:

    【解决方案2】:

    当您在寻找“低级”定义时,唯一合法的来源可能是我们的老朋友 - JLS。虽然在这种情况下没有给出明确的定义,但它使用每个术语的上下文可能就足够了。

    派送

    在确定调用哪个方法的过程中确实提到了这个术语。

    15.12.2. Compile-Time Step 2: Determine Method Signature

    第二步搜索上一步确定的类型 成员方法。此步骤使用方法的名称和参数 用于定位 accessibleapplicable 的方法的表达式, 也就是说,可以在给定的情况下正确调用的声明 论据。

    这样的方法可能不止一种,在这种情况下 最具体的一个被选中。描述符(签名加返回 type) 最具体的方法是在运行时用于 执行方法分派。一个方法是适用的,如果它是 适用于严格调用之一

    关于什么是“最具体”的方法的详细说明在15.12.2.5 选择最具体的方法中完成。

    至于“动态调度”,

    JLS 12.5. Creation of New Class Instances:

    与 C++ 不同,Java 编程语言不指定更改 在创建新类实例期间方法分派的规则。 如果调用了在对象的子类中被覆盖的方法 被初始化,然后使用这些覆盖方法,甚至在之前 新对象已完全初始化。

    包括

    示例 12.5-2。实例创建期间的动态调度

    class Super {
    
      Super() {
          printThree();
      }
    
      void printThree() {
          System.out.println("three");
      }
    }
    
    class Test extends Super {
    
      int three = 3;
    
      void printThree() {
          System.out.println(three);
      }
    
      public static void main(String[] args) {
          Test t = new Test();
          t.printThree();
      }
    }
    

    输出:

    0
    3

    这是因为在构造函数调用链中,Super 的构造函数调用了printThree,但是由于动态调度,Test 中的方法被调用,并且是在字段初始化之前。

    绑定

    该术语用于类成员访问的上下文中。

    Example 15.11.1-1. Static Binding for Field Access 演示了早期和晚期绑定。我将总结那里为我们这些懒惰者提供的示例:

    class S {
        int x = 0;
        int z() { return x; }
    }
    
    class T extends S {
        int x = 1;
        int z() { return x; }
    }
    
    public class Test1 {
    
        public static void main(String[] args) {
            S s = new T();
            System.out.println("s.x=" + s.x);
            System.out.println("s.x=" + s.z());
        }
    }
    

    输出:

    s.x=0
    s.x=1

    显示该字段使用“早期绑定”,而实例方法使用“后期绑定”:

    由于缺少对字段访问的动态查找,因此程序可以通过以下方式有效运行 直接的实现。后期绑定和覆盖的功能是可用的,但是 仅在使用实例方法时。

    绑定也用于确定泛型的类型,

    8. Classes

    类可以是通用的(第 8.1.2 节),也就是说,它们可以声明类型变量,其绑定在类的不同实例之间可能不同。

    意思是如果你创建了List<String>的2个实例,String在这两个实例中的绑定是不同的。

    这也适用于原始类型:

    4.8. Raw Types

    class Outer<T>{
        T t;
        class Inner {
            T setOuterT(T t1) { t = t1; return t; }
        }
    }
    

    Inner 的成员类型取决于 Outer 的类型参数。如果 Outer 是原始的,则 Inner 也必须被视为原始的,因为 T 没有有效的绑定。

    意味着声明 Outer outer(这将生成原始类型警告)不允许确定 T 的类型(显然 - 它没有在声明中定义)。

    【讨论】:

      【解决方案3】:

      这些是通用术语,您可以这样总结:当某些事物(方法或对象)是静态/早期时,这意味着事物是在编译时配置的,并且在运行时没有歧义,例如在以下代码:

      class A {
          void methodX() {
          System.out.print("i am A");
          }
       }
      

      如果我们创建一个A的实例并调用methodX(),没有什么是雄心勃勃的,一切都是在编译时配置的,但是如果我们有以下代码

      class B extends A {
        void methodX() {
          System.out.print("i am B");
         }
       }
      ....
      A objX= new B();
      objX.methodX();
      

      直到运行时才知道方法 x 的输出,因此该方法是动态绑定/调度的(对于方法 link,我们可以使用术语调度而不是绑定)。

      【讨论】:

      • 您解释了方法调度。绑定呢?这是一个密切相关的术语,但却是独立的概念。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 2015-03-10
      • 2020-09-29
      • 2011-01-03
      • 2012-05-24
      相关资源
      最近更新 更多