Java中的后期绑定

我已经搜索了关于堆栈溢出的后期绑定的所有类似问题,并且我非常不同意将此问题标记为重复的任何人。 首先,我在另一个问题上找到了这个例子,但是我不明白在编译期间什么时候决定什么以及什么时候在运行时确定了什么我应该知道。 基本上,我的问题的症结归结为两件事:

  • 本例中的内容必须使我得出一个逻辑结论:一个方法是后期绑定,另一个方法是早期绑定

  • 我如何知道在Java中运行时或编译时决定执行哪个版本的方法的决定

码:

class A { public void foo() { System.out.println("Class A"); } } class B extends A { public void foo() { System.out.println("Class B"); } } public class C { public static void main(String [] args) { A a=new A(); B b=new B(); A ref=null; /* early binding --- calls method foo() of class A and decided at compile time */ a.foo(); /* early binding --- calls method foo() of class B and decided at compile time */ b.foo(); /* late binding --- --- calls method foo() of class B and decided at Run time */ ref=b; ref.foo(); } } 

在所有方面都错了。 根据对象的运行时类型,在运行时决定要调用的方法,在每种情况下都是如此。 在编译时做出的唯一决定是调用final,private或static方法,或者在一组重载方法中进行选择(如果重载方法不是final,private或static,它们仍然可以导致运行时选择。)

Java对所有非最终的非私有实例方法使用后期绑定。 这就是多态性的实现方式。 您评论的所有电话都是在运行时确定的。

 A a=new A(); a.foo(); 

a引用A对象,因此将找到,绑定和使用A的实现。

 B b=new B(); b.foo(); 

b引用B对象,因此将找到,绑定和使用B的实现。

 ref=b; ref.foo(); 

ref引用一个B对象,因此将找到,绑定和使用B的实现。

变量的静态(声明)类型仅由编译器用于validation在该类型上是否可以访问此类方法。

有关:

  • 什么是早期和晚期绑定?

这里的所有答案大多都是正确的,但是关于Java中的后期绑定有一个关键点缺失。
如果我们按照后期绑定的定义,Java不会执行“由书”后期绑定。 书籍定义forms中的后期绑定意味着编译器不应该执行任何参数检查,不对类型检查进行类型检查,并且应将其全部留给运行时 – 因为编译器可能无法访问方法实现代码(例如, COM编程)。 但是,Java在编译时确实会validation,即使在多态方案中,被调用的方法和方法签名确实存在于限定方法的表达式的类型层次结构中的某处。 例如,假设我在ref上调用了一个方法foo1,它在A或B中都不存在:

 A ref=null; ref=new B(); ref.foo1(); //This will not compile in Java, because java will check at compile time //for the method foo1 in the type hierarchy of A, which is the type of the // variable ref at compile time. //In pure late binding, however this would pass compilation and //throw an error at runtime. 

后期绑定方案中,确定方法foo1()是否存在且具有正确数量的参数仅在运行时进行 。 但是在Java中,在编译时进行了一定程度的检查,以确保具有正确数量的参数的方法确实存在于类型层次结构中的某个位置。
我认为Java确实执行后期绑定的唯一一次是使用reflection来调用方法。 Java所做的最好被称为动态调度而不是后期绑定,但是每个人都称它为Java后期绑定,因此存在混淆。

考虑一下这句话

  A ref; //reference of A ref = new B();//Object of B ref.f2(); 

这里ref是class A的引用,它具有class B对象的地址f2()是一个overridden方法。

当编译器检测到这样的语句时,它不会将函数调用与任何定义绑定。 它只validation通话。

这些调用的绑定留给运行时环境。 在程序运行时,系统识别对象的数据类型,并使用对象类提供的函数定义绑定函数调用。 函数调用和函数定义之间的这种类型的绑定称为“后期绑定”或“运行时绑定”或“运行时多态”或“动态方法调度”。

经历这个问题并阅读我的答案示例也在那里。

当您在任何对象上调用方法时,请始终记住在inheritance中将调用“最少修改版本”的方法。 这只不过是从层次结构中动态选择方法版本。