В чем разница между ранней и поздней привязкой?

В чем разница между ранним и поздним связыванием?

Ответов (8)

Решение

Короткий ответ заключается в том, что ранняя (или статическая) привязка относится к привязке во время компиляции, а поздняя (или динамическая) привязка относится к привязке во время выполнения (например, когда вы используете отражение).

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 из дочернего элемента, так как в method1 у подростка нет method1.

Обратите внимание, что если у дочернего элемента не было method1, то код в основном не компилировался.

Полиморфизм времени компиляции также называется перегрузкой, ранним связыванием или статическим связыванием, когда у нас есть одно и то же имя метода с различным поведением. Реализуя несколько прототипов одного и того же метода, в нем происходит различное поведение. Раннее связывание относится к первой компиляции программы. Но при позднем связывании объект выполняется в программе. Также называется динамическим связыванием или переопределением или полиморфизмом времени выполнения.

Аналогичный, но более подробный ответ из книги Герберта Шильдта С ++: -

Раннее связывание относится к событиям, которые происходят во время компиляции. По сути, раннее связывание происходит, когда вся информация, необходимая для вызова функции, известна во время компиляции. (Иными словами, раннее связывание означает, что объект и вызов функции связаны во время компиляции.) Примеры раннего связывания включают обычные вызовы функций (включая стандартные библиотечные функции), вызовы перегруженных функций и перегруженные операторы. Главное преимущество раннего связывания - эффективность. Поскольку вся информация, необходимая для вызова функции, определяется во время компиляции, эти типы вызовов функций выполняются очень быстро.

Противоположностью раннего связывания является позднее связывание. Позднее связывание относится к вызовам функций, которые не разрешаются до времени выполнения. Виртуальные функции используются для достижения позднего связывания. Как вы знаете, когда доступ осуществляется через базовый указатель или ссылку, фактически вызываемая виртуальная функция определяется типом объекта, на который указывает указатель. Поскольку в большинстве случаев это невозможно определить во время компиляции, объект и функция не связываются до времени выполнения. Главное преимущество позднего связывания - гибкость. В отличие от раннего связывания, позднее связывание позволяет создавать программы, которые могут реагировать на события, происходящие во время выполнения программы, без необходимости создания большого количества «кода на случай непредвиденных обстоятельств». Имейте в виду, что, поскольку вызов функции не разрешается до времени выполнения, позднее связывание может несколько замедлить время выполнения. Однако сегодня

Самый простой пример на 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

Раннее связывание происходит во время компиляции, а позднее связывание - во время выполнения.

Взято непосредственно из 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:
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) может быть очень далек от определения метода, и если вы смотрите на определение метода, было бы неплохо увидеть его реализацию.

Основным преимуществом позднего связывания является то, что он упрощает такие вещи, как инверсия управления, а также некоторые другие виды использования полиморфизма и утиной печати (если ваш язык поддерживает такие вещи).

В интерпретируемых языках разница немного тоньше.

Рубин:

# 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 отлично использует позднее связывание, чтобы уменьшить объем конфигурации, необходимой для запуска вашего приложения.