В настоящее время я выполняю задание для одного из моих классов, и в нем я должен привести примеры статической и динамической привязки с использованием синтаксиса Java .
Я понимаю базовую концепцию, что статическое связывание происходит во время компиляции, а динамическое связывание происходит во время выполнения, но я не могу понять, как они на самом деле работают конкретно.
Я нашел в Интернете пример статической привязки, который дает следующий пример:
public static void callEat(Animal animal) {
System.out.println("Animal is eating");
}
public static void callEat(Dog dog) {
System.out.println("Dog is eating");
}
public static void main(String args[])
{
Animal a = new Dog();
callEat(a);
}
И что это будет напечатать «животное ест», потому что вызов callEat
использует статическую привязку , но я не уверен, почему это считается статической привязкой.
Пока что ни один из источников, которые я видел, не смог объяснить это так, как я могу понять.
java
dynamic-binding
static-binding
user2309750
источник
источник
Ответы:
Из сообщения в блоге, которое посетил Ява :
источник
Подключение вызова метода к телу метода называется привязкой. Как сказал Маулик, «статическая привязка использует информацию типа (класс в Java) для привязки, в то время как динамическая привязка использует объект для разрешения привязки». Итак, этот код:
Результат будет: собака ест ... потому что использует ссылку на объект, чтобы найти, какой метод использовать. Если мы изменим приведенный выше код на этот:
Он произведет: животное ест ... потому что это статический метод, поэтому он использует Type (в данном случае Animal), чтобы решить, какой статический метод вызывать. Помимо статических методов, частные и конечные методы используют один и тот же подход.
источник
a
это на самом делеDog
во время компиляции?Компилятор знает только, что тип "a"
Animal
; это происходит во время компиляции, из-за чего это называется статической привязкой (перегрузка метода). Но если это динамическое связывание, тогда он вызоветDog
метод класса. Вот пример динамической привязки.Продукт: Метод Собаки изнутри.
источник
Ну чтобы понять, как на самом деле работает статическая и динамическая привязка ? или как они идентифицируются компилятором и JVM?
Давайте рассмотрим пример ниже, в котором
Mammal
родительский класс имеет метод,speak()
иHuman
класс расширяетсяMammal
, переопределяетspeak()
метод, а затем снова перегружает егоspeak(String language)
.Когда мы компилируем приведенный выше код и пытаемся взглянуть на байт-код, используя
javap -verbose OverridingInternalExample
, мы можем видеть, что компилятор генерирует таблицу констант, в которой он назначает целочисленные коды каждому вызову метода и байтовый код для программы, которую я извлек и включил в саму программу ( см. комментарии под каждым вызовом метода)Глядя на коде выше мы видим , что в байткодах из
humanMammal.speak()
,human.speak()
иhuman.speak("Hindi")
совершенно разные (invokevirtual #4
,invokevirtual #7
,invokevirtual #9
) , так как компилятор способен различать между ними на основе списка аргументов и ссылке класса. Поскольку все это разрешается во время компиляции статически, поэтому перегрузка метода известна как статический полиморфизм или статическое связывание .Но байт-код для
anyMammal.speak()
иhumanMammal.speak()
такой же (invokevirtual #4
), потому что в соответствии с компилятором оба метода вызываются поMammal
ссылке.Итак, теперь возникает вопрос, если оба вызова метода имеют одинаковый байт-код, тогда как JVM узнает, какой метод вызывать?
Что ж, ответ скрыт в самом байт-коде, и это
invokevirtual
набор инструкций. JVM используетinvokevirtual
инструкцию для вызова Java-эквивалента виртуальных методов C ++. В C ++, если мы хотим переопределить один метод в другом классе, нам нужно объявить его виртуальным, но в Java все методы являются виртуальными по умолчанию, потому что мы можем переопределить каждый метод в дочернем классе (кроме частных, конечных и статических методов).В Java каждая ссылочная переменная содержит два скрытых указателя
Таким образом, все ссылки на объекты косвенно содержат ссылку на таблицу, которая содержит все ссылки на методы этого объекта. В Java эта концепция позаимствована из C ++, и эта таблица известна как виртуальная таблица (vtable).
Vtable - это структура, подобная массиву, которая содержит имена виртуальных методов и их ссылки на индексы массива. JVM создает только одну виртуальную таблицу для каждого класса при загрузке класса в память.
Поэтому всякий раз, когда JVM сталкивается с
invokevirtual
набором инструкций, она проверяет vtable этого класса на наличие ссылки на метод и вызывает конкретный метод, который в нашем случае является методом объекта, а не ссылкой.Поскольку все это разрешается только во время выполнения, а во время выполнения JVM узнает, какой метод вызывать, поэтому переопределение метода известно как динамический полиморфизм или просто полиморфизм или динамическое связывание .
Вы можете прочитать об этом более подробно в моей статье Как JVM обрабатывает перегрузку и переопределение методов изнутри .
источник
Существует три основных различия между статической и динамической привязкой при разработке компиляторов и способах передачи переменных и процедур в среду выполнения . Эти различия заключаются в следующем:
Статическое связывание : при статическом связывании обсуждаются три следующие проблемы:
Определение процедуры
Объявление имени (переменной и т. Д.)
Объем декларации
Динамическое связывание. При динамическом связывании возникают три проблемы:
Активация процедуры
Привязка имени
Срок службы привязки
источник
С помощью статического метода в родительском и дочернем классе: Static Binding
Динамическое связывание:
источник
Все ответы здесь верны, но я хочу добавить то, чего не хватает. когда вы переопределяете статический метод, похоже, что мы переопределяем его, но на самом деле это не переопределение метода. Вместо этого это называется скрытием метода. Статические методы нельзя переопределить в Java.
Посмотрите на пример ниже:
При динамическом связывании метод вызывается в зависимости от типа ссылки, а не типа объекта, который содержит ссылочная переменная. Здесь происходит статическое связывание, поскольку скрытие метода не является динамическим полиморфизмом. Если вы удалите ключевое слово static перед eat () и сделаете его нестатическим методом, он покажет вам динамический полиморфизм, а не скрытие метода.
я нашел ссылку ниже, чтобы поддержать свой ответ: https://youtu.be/tNgZpn7AeP0
источник
В случае статического связывания тип объекта определяется во время компиляции, тогда как в случае динамического связывания тип объекта определяется во время выполнения.
источник
Поскольку компилятор знает привязку во время компиляции. Если вы вызываете метод, например, в интерфейсе, компилятор не может знать, и привязка разрешается во время выполнения, потому что фактический объект, имеющий вызванный метод, может быть одним из нескольких. Следовательно, это время выполнения или динамическое связывание.
Ваш вызов привязан к классу Animal во время компиляции, потому что вы указали тип. Если вы передадите эту переменную в другой метод где-то еще, никто не узнает (кроме вас, потому что вы ее написали), что это за класс. Единственная подсказка - заявленный тип Animal.
источник