В чем разница между ранним и поздним связыванием?
В чем разница между ранним и поздним связыванием?
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) может быть очень далек от определения метода, и если вы посмотрите на определение метода, было бы неплохо увидеть реализацию.
Основное преимущество позднего связывания заключается в том, что оно облегчает такие вещи, как инвертирование контроля, а также некоторые другие виды использования полиморфизма и утки (если ваш язык поддерживает такие вещи).
Подобный, но более подробный ответ из книги Герберта Шильдта 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")
Чтобы использовать раннее связывание, сначала необходимо установить ссылку в вашем проекте на приложение, которым вы хотите манипулировать. В редакторе VB любого приложения Office или в самом 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 широко использует позднюю привязку, чтобы уменьшить объем конфигурации, необходимой для работы вашего приложения.
Самый простой пример на 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
Раннее связывание происходит во время компиляции, а позднее связывание - во время выполнения.
Полиморфизм времени компиляции также называется перегрузкой или ранним связыванием или статическим связыванием, когда у нас одно и то же имя метода с различным поведением. При реализации нескольких прототипов одного и того же метода и различного поведения происходит в нем. Раннее связывание относится к первой компиляции программы. Но в конце связывание объекта происходит во время выполнения программы. Также называется динамическим связыванием или переопределением или полиморфизмом времени выполнения.
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 и teenager, но при позднем связывании (во время выполнения) он будет проверять методы, которые были переопределены во время выполнения.
Следовательно, method1 (от потомка - раннее связывание) будет переопределен method1 от взрослого во время выполнения (позднее связывание). Затем он будет реализовывать method1 от потомка, так как нет метода1 в method1 у подростка.
Обратите внимание, что если у child нет метода method1, код в main не будет компилироваться.