Может ли кто-нибудь предоставить простой пример, объясняющий разницу между динамическим и статическим полиморфизмом в Java?
Может ли кто-нибудь предоставить простой пример, объясняющий разницу между динамическим и статическим полиморфизмом в Java?
Ответы:
Полиморфизм
1. Статическое связывание / связывание во время компиляции / раннее связывание / перегрузка метода (в том же классе)
2. Динамическая привязка / привязка во время выполнения / поздняя привязка / переопределение метода (в разных классах)
class Calculation {
void sum(int a,int b){System.out.println(a+b);}
void sum(int a,int b,int c){System.out.println(a+b+c);}
public static void main(String args[]) {
Calculation obj=new Calculation();
obj.sum(10,10,10); // 30
obj.sum(20,20); //40
}
}
class Animal {
public void move(){
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move();//output: Animals can move
b.move();//output:Dogs can walk and run
}
}
Animal reference but Dog object
, почему мы не можем использовать Dog reference and dog object
?
Перегрузка метода была бы примером статического полиморфизма
тогда как переопределение было бы примером динамического полиморфизма.
Потому что в случае перегрузки во время компиляции компилятор знает, какой метод связать с вызовом. Однако он определяется во время выполнения для динамического полиморфизма
Динамический (во время выполнения) полиморфизм - это полиморфизм, существующий во время выполнения. Здесь компилятор Java не понимает, какой метод вызывается во время компиляции. Только JVM решает, какой метод вызывается во время выполнения. Перегрузка метода и переопределение метода с использованием методов экземпляра являются примерами динамического полиморфизма.
Например,
Рассмотрим приложение, которое сериализует и десериализует различные типы документов.
У нас может быть «Документ» в качестве базового класса и производные от него классы различных типов документов. Например, XMLDocument, WordDocument и т. Д.
Класс документа будет определять методы «Serialize ()» и «De-serialize ()» как виртуальные, и каждый производный класс будет реализовывать эти методы по-своему на основе фактического содержимого документов.
Когда различные типы документов необходимо сериализовать / десериализовать, на объекты документа будет ссылаться ссылка на класс (или указатель) «Документ», а при вызове метода «Serialize ()» или «De-serialize ()» на нем вызываются соответствующие версии виртуальных методов.
Статический (во время компиляции) полиморфизм - это полиморфизм, проявляемый во время компиляции. Здесь компилятор Java знает, какой метод вызывается. Перегрузка методов и переопределение методов с использованием статических методов; переопределение метода с использованием частных или конечных методов являются примерами статического полиморфизма
Например,
У объекта сотрудника может быть два метода print (): один не принимает аргументов, а другой принимает строку префикса, которая будет отображаться вместе с данными сотрудника.
С учетом этих интерфейсов, когда метод print () вызывается без каких-либо аргументов, компилятор, глядя на аргументы функции, знает, какая функция должна быть вызвана, и соответственно генерирует объектный код.
Для более подробной информации прочтите «Что такое полиморфизм» (Google it).
Связывание относится к связи между вызовом метода и определением метода.
На этой картинке хорошо видно, что является обязательным.
На этом рисунке вызов «a1.methodOne ()» привязан к соответствующему определению methodOne (), а вызов «a1.methodTwo ()» привязан к соответствующему определению methodTwo ().
Для каждого вызова метода должно быть правильное определение метода. Это правило в java. Если компилятор не видит правильного определения метода для каждого вызова метода, он выдает ошибку.
Теперь перейдем к статической привязке и динамической привязке в java.
Статическая привязка в Java:
Статическая привязка - это привязка, которая происходит во время компиляции. Это также называется ранним связыванием, потому что связывание происходит до того, как программа действительно запускается.
,
Статическое связывание можно продемонстрировать, как показано на рисунке ниже.
На этом рисунке 'a1' - это ссылочная переменная типа Class A, указывающая на объект класса A. 'a2' также ссылочная переменная типа класса A, но указывающая на объект класса B.
Во время компиляции при связывании компилятор не проверяет тип объекта, на который указывает конкретная ссылочная переменная. Он просто проверяет тип ссылочной переменной, через которую вызывается метод, и проверяет, существует ли определение метода для него в этом типе.
Например, для вызова метода «a1.method ()» на изображении выше компилятор проверяет, существует ли определение метода для method () в классе A. Поскольку «a1» является типом класса A. Аналогично, для вызова метода «a2.method ()» он проверяет, существует ли определение метода для method () в классе A. Поскольку «a2» также является типом класса A. Он не проверяет, на какой объект указывают «a1» и «a2». Этот тип привязки называется статической привязкой.
Динамическое связывание в Java:
Динамическое связывание - это связывание, которое происходит во время выполнения. Это также называется поздним связыванием, потому что связывание происходит, когда программа действительно работает.
Во время выполнения для привязки используются реальные объекты. Например, для вызова «a1.method ()» на рисунке выше будет вызван метод () фактического объекта, на который указывает «a1». Для вызова «a2.method ()» будет вызван метод () фактического объекта, на который указывает «a2». Этот тип привязки называется динамической привязкой.
Динамическое связывание приведенного выше примера можно продемонстрировать, как показано ниже.
Ссылка на статическую привязку и динамическую привязку в java
Полиморфизм: полиморфизм - это способность объекта принимать разные формы. Наиболее распространенное использование полиморфизма в ООП происходит, когда ссылка на родительский класс используется для ссылки на объект дочернего класса.
Динамическое связывание / полиморфизм времени выполнения:
Полиморфизм времени выполнения, также известный как переопределение метода. В этом механизме вызов переопределенной функции разрешается во время выполнения.
public class DynamicBindingTest {
public static void main(String args[]) {
Vehicle vehicle = new Car(); //here Type is vehicle but object will be Car
vehicle.start(); //Car's start called because start() is overridden method
}
}
class Vehicle {
public void start() {
System.out.println("Inside start method of Vehicle");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Inside start method of Car");
}
}
Вывод:
Метод внутреннего старта автомобиля
Статическое связывание / полиморфизм времени компиляции:
Решение о том, какой метод вызывать, решается только во время компиляции.
public class StaticBindingTest {
public static void main(String args[]) {
Collection c = new HashSet();
StaticBindingTest et = new StaticBindingTest();
et.sort(c);
}
//overloaded method takes Collection argument
public Collection sort(Collection c){
System.out.println("Inside Collection sort method");
return c;
}
//another overloaded method which takes HashSet argument which is sub class
public Collection sort(HashSet hs){
System.out.println("Inside HashSet sort method");
return hs;
}
}
Вывод: метод сортировки внутри коллекции
перегрузка метода является примером статического полиморфизма времени компиляции, поскольку привязка метода между вызовом метода и определением метода происходит во время компиляции и зависит от ссылки на класс (ссылка создается во время компиляции и переходит в стек).
переопределение метода является примером динамического полиморфизма времени выполнения, потому что привязка метода между вызовом метода и определением метода происходит во время выполнения и зависит от объекта класса (объект, созданный во время выполнения, отправляется в кучу).
Проще говоря:
Статический полиморфизм : одно и то же имя метода перегружено с другим типом или количеством параметров в одном классе (разные сигнатуры). Целевой вызов метода разрешается во время компиляции.
Динамический полиморфизм : один и тот же метод переопределяется одинаковой сигнатурой в разных классах. . Тип объекта, для которого вызывается метод, неизвестен во время компиляции, но будет определен во время выполнения.
Обычно перегрузка не рассматривается как полиморфизм.
Со страницы руководства по Java :
Подклассы класса могут определять собственное уникальное поведение и в то же время разделять некоторые из функций родительского класса.
Generally overloading won't be considered as polymorphism.
не могли бы вы уточнить этот момент.
Перегрузка метода известна как статический полиморфизм, а также известна как полиморфизм времени компиляции или статическое связывание. поскольку вызовы перегруженных методов разрешаются компилятором во время компиляции на основе списка аргументов и ссылки, по которой мы вызываем метод.
И методы Перекрытие известно как Dynamic полиморфизм или просто полиморфизм или время выполнения метод отправка или динамическое связывание , поскольку переопределяется метод вызов разрешаются во время выполнения.
Чтобы понять, почему это так, давайте возьмем пример Mammal
и Human
класс
class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
}
Я включил вывод, а также байт-код в следующие строки кода
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
И, посмотрев на приведенный выше код, мы видим, что байт-коды humanMammal.speak (), human.speak () и human.speak («хинди») совершенно разные, потому что компилятор может различать их на основе списка аргументов. и ссылка на класс. Вот почему перегрузка метода известна как статический полиморфизм. .
Но байт-код для anyMammal.speak () и humanMammal.speak () такой же, потому что в соответствии с компилятором оба метода вызываются по ссылке Mammal, но вывод для обоих вызовов методов отличается, потому что во время выполнения JVM знает, какой объект удерживает ссылка, и вызывает JVM метод объекта, поэтому переопределение метода известно как динамический полиморфизм.
Таким образом, из приведенного выше кода и байт-кода ясно, что на этапе компиляции метод вызова рассматривается из ссылочного типа. Но во время выполнения метод будет вызван из объекта, который содержит ссылка.
Если вы хотите узнать больше об этом, вы можете прочитать больше о том, как JVM обрабатывает перегрузку и переопределение методов внутренне .
Статический полиморфизм: решение о том, какой метод выполнить, принимается во время компиляции. Примером этого может быть перегрузка метода.
Динамический полиморфизм: решение о выборе метода для выполнения устанавливается во время выполнения. Примером этого может быть переопределение метода.
Полиморфизм относится к способности объекта вести себя по-разному для одного и того же триггера.
Статический полиморфизм (полиморфизм времени компиляции)
Динамический полиморфизм (полиморфизм времени выполнения)
Полиморфизм времени компиляции (статическое связывание / раннее связывание): в статическом полиморфизме, если мы вызываем метод в нашем коде, то определение того, какое определение этого метода должно быть вызвано на самом деле, разрешается только во время компиляции.
(или)
Во время компиляции Java знает, какой метод вызывать, проверяя сигнатуры методов. Итак, это называется полиморфизмом времени компиляции или статическим связыванием.
Динамический полиморфизм (полиморфизм позднего связывания / времени выполнения): во время выполнения Java ожидает, пока среда выполнения не определит, на какой объект фактически указывает ссылка. Разрешение метода было принято во время выполнения, поэтому мы называем это полиморфизмом времени выполнения.
Рассмотрим код ниже:
public class X
{
public void methodA() // Base class method
{
System.out.println ("hello, I'm methodA of class X");
}
}
public class Y extends X
{
public void methodA() // Derived Class method
{
System.out.println ("hello, I'm methodA of class Y");
}
}
public class Z
{
public static void main (String args []) {
//this takes input from the user during runtime
System.out.println("Enter x or y");
Scanner scanner = new Scanner(System.in);
String value= scanner.nextLine();
X obj1 = null;
if(value.equals("x"))
obj1 = new X(); // Reference and object X
else if(value.equals("y"))
obj2 = new Y(); // X reference but Y object
else
System.out.println("Invalid param value");
obj1.methodA();
}
}
Теперь, глядя на код, вы никогда не сможете сказать, какая реализация methodA () будет выполнена, потому что это зависит от того, какое значение пользователь задает во время выполнения. Таким образом, только во время выполнения решается, какой метод будет вызван. Следовательно, полиморфизм времени выполнения.
Перегрузка метода - это полиморфизм времени компиляции, давайте рассмотрим пример, чтобы понять концепцию.
class Person //person.java file
{
public static void main ( String[] args )
{
Eat e = new Eat();
e.eat(noodle); //line 6
}
void eat (Noodles n) //Noodles is a object line 8
{
}
void eat ( Pizza p) //Pizza is a object
{
}
}
В этом примере у Person есть метод eat, который означает, что он может съесть пиццу или лапшу. Что метод eat перегружен, когда мы компилируем этот Person.java, компилятор разрешает вызов метода "e.eat (noodles) [который находится в строке 6] с определением метода, указанным в строке 8, то есть это метод, который принимает лапшу в качестве параметра и весь процесс выполняется компилятором, поэтому это полиморфизм времени компиляции.Процесс замены вызова метода определением метода называется связыванием, в этом случае это выполняется компилятором, поэтому он вызывается как раннее связывание.
Следуя ответу Нареша, динамический полиморфизм является только «динамическим» в Java из-за наличия виртуальной машины и ее способности интерпретировать код во время выполнения, а не код, выполняющийся изначально.
В C ++ это должно быть разрешено во время компиляции, если он компилируется в собственный двоичный файл с использованием gcc, очевидно; однако скачки и переходы во время выполнения в виртуальной таблице по-прежнему называются «поисковыми» или «динамическими». Если C наследует B, и вы объявляете , c уже будет указывать на внешний объект C, и указатель будет передан в C :: method1 () в текстовом сегменте. См .: http://www.programmersought.com/article/2572545946/B* b = new C(); b->method1();
, компилятор разрешит b, чтобы указать на объект B внутри C (для простого класса наследует ситуацию класса, объект B внутри C и C будет начинаться с того же адреса памяти, поэтому ничего необходимо сделать; он будет указывать на vptr, который они оба используют). Если C наследует B и A, таблица виртуальных функций объекта A внутри записи C для метода1 будет иметь преобразователь, который смещает указатель на начало инкапсулирующего объекта C, а затем передает его в реальный A :: method1 () в текстовом сегменте, который C переопределил. ДляC* c = new C(); c->method1()
В java для B b = new C(); b.method1();
виртуальная машина может динамически проверять тип объекта в паре с b, передавать правильный указатель и вызывать правильный метод. Дополнительный шаг виртуальной машины устраняет необходимость в таблицах виртуальных функций или типе, определяемом во время компиляции, даже если он может быть известен во время компиляции. Это просто другой способ сделать это, который имеет смысл, когда задействована виртуальная машина, а код компилируется только в байт-код.