早期绑定和后期绑定有什么区别?
8 回答
简短的回答是,早期(或静态)绑定是指编译时绑定,后期(或动态)绑定是指运行时绑定(例如,当您使用反射时)。
在编译语言中,差异是明显的。
爪哇:
//early binding:
public create_a_foo(*args) {
return new Foo(args)
}
my_foo = create_a_foo();
//late binding:
public create_something(Class klass, *args) {
klass.new_instance(args)
}
my_foo = create_something(Foo);
在第一个示例中,编译器可以在编译时执行各种简洁的操作。其次,您只需要希望使用该方法的人负责任地这样做。(当然,较新的 JVM 支持这种Class<? extends Foo> klass
结构,可以大大降低这种风险。)
另一个好处是 IDE 可以热链接到类定义,因为它是在方法中声明的。对 create_something(Foo) 的调用可能与方法定义相距甚远,如果您正在查看方法定义,可能会很高兴看到实现。
后期绑定的主要优点是它使控制反转之类的事情变得更容易,以及多态性和鸭子类型的某些其他用途(如果您的语言支持这样的事情)。
Herbert Schildt C++ 书中类似但更详细的答案:-
早期绑定是指在编译时发生的事件。本质上,当调用函数所需的所有信息在编译时已知时,就会发生早期绑定。(换句话说,早期绑定意味着在编译期间绑定对象和函数调用。)早期绑定的示例包括普通函数调用(包括标准库函数)、重载函数调用和重载运算符。早期绑定的主要优点是效率。因为调用函数所需的所有信息都是在编译时确定的,所以这些类型的函数调用非常快。
早期绑定的反面是后期绑定。后期绑定是指直到运行时才解析的函数调用。虚函数用于实现后期绑定。如您所知,当通过基指针或引用访问时,实际调用的虚函数由指针指向的对象类型决定。因为在大多数情况下,这在编译时无法确定,所以对象和函数直到运行时才链接。后期绑定的主要优点是灵活性。与早期绑定不同,后期绑定允许您创建可以响应程序执行时发生的事件的程序,而无需创建大量“应急代码”。请记住,由于直到运行时才解析函数调用,所以后期绑定可能会使执行时间变慢。然而今天,
直接取自http://word.mvps.org/fAQs/InterDev/EarlyvsLateBinding.htm
有两种方法可以使用自动化(或 OLE 自动化)以编程方式控制另一个应用程序。
后期绑定使用 CreateObject 创建应用程序对象的实例,然后您可以对其进行控制。例如,要使用后期绑定创建新的 Excel 实例:
Dim oXL As Object Set oXL = CreateObject("Excel.Application")
另一方面,要操作现有的 Excel 实例(如果 Excel 已打开),您将使用 GetObject(无论您使用的是早期绑定还是后期绑定):
Dim oXL As Object Set oXL = GetObject(, "Excel.Application")
要使用早期绑定,首先需要在项目中设置对要操作的应用程序的引用。在任何 Office 应用程序的 VB 编辑器中,或在 VB 本身中,您可以通过选择工具 + 参考,然后从列表中选择所需的应用程序(例如“Microsoft Excel 8.0 对象库”)来执行此操作。
要使用早期绑定创建新的 Excel 实例:
Dim oXL As Excel.Application Set oXL = New Excel.Application
在这两种情况下,顺便说一句,您可以先尝试获取现有的 Excel 实例,如果返回错误,您可以在错误处理程序中创建一个新实例。
在解释型语言中,差异要微妙一些。
红宝石:
# early binding:
def create_a_foo(*args)
Foo.new(*args)
end
my_foo = create_a_foo
# late binding:
def create_something(klass, *args)
klass.new(*args)
end
my_foo = create_something(Foo)
因为 Ruby(通常)没有被编译,所以没有编译器来做漂亮的前期工作。JRuby 的发展意味着现在编译了更多的 Ruby,这使得它更像上面的 Java。
IDE 的问题仍然存在:如果您对类定义进行硬编码,像 Eclipse 这样的平台可以查找类定义,但如果将它们留给调用者则不能。
控制反转在 Ruby 中并不是很流行,可能是因为它具有极高的运行时灵活性,但 Rails 充分利用后期绑定来减少启动应用程序所需的配置量。
public class child()
{ public void method1()
{ System.out.println("child1");
}
public void method2()
{ System.out.println("child2");
}
}
public class teenager extends child()
{ public void method3()
{ System.out.println("teenager3");
}
}
public class adult extends teenager()
{
public void method1()
{ System.out.println("adult1);
super.method1();
}
}
//In java
public static void main(String []args)
{ ((teenager)var).method1();
}
这将打印出来
adult1
child1
在早期绑定中,编译器将可以访问 child 和 Teen 中的所有方法,但在后期绑定中(在运行时),它将检查在运行时被覆盖的方法。
因此,method1(来自child - 早期绑定)将在运行时被成人的method1覆盖(后期绑定)然后它将从child实现method1,因为在青少年的method1中没有method1。
请注意,如果 child 没有 method1,则 main 中的代码将无法编译。
当我们具有相同的方法名称但行为不同时,编译时多态性也称为重载或早期绑定或静态绑定。通过实现相同方法的多个原型,其中会发生不同的行为。早期绑定是指程序的第一次编译。但是在后期绑定对象是运行时发生在程序中。也称为动态绑定或覆盖或运行时多态性。
java中最简单的例子:
早期(静态或重载)绑定:
public class Duck {
public static void quack(){
System.out.println("Quack");
}
}
public class RubberDuck extends Duck {
public static void quack(){
System.out.println("Piiiiiiiiii");
}
}
public class EarlyTest {
public static void main(String[] args) {
Duck duck = new Duck();
Duck rubberduck = new RubberDuck();
duck.quack();
rubberduck.quack(); //early binding - compile time
}
}
结果是:
Quack
Quack
而对于后期(动态或覆盖)绑定:
public class Duck {
public void quack(){
System.out.println("Quack");
}
}
public class RubberDuck extends Duck {
public void quack(){
System.out.println("Piiiiiiiiii");
}
}
public class LateTest {
public static void main(String[] args){
Duck duck = new Duck();
Duck rubberduck = new RubberDuck();
duck.quack();
rubberduck.quack(); //late binding - runtime
}
}
结果是:
Quack
Piiiiiiiiii
早期绑定发生在编译时,而后期绑定发生在运行时。