Чи може хтось надати простий приклад, який пояснює різницю між динамічним та статичним поліморфізмом на 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 ()" як віртуальний, і кожен похідний клас реалізує ці методи по-своєму, виходячи з фактичного змісту документів.
Коли різні типи документів потрібно серіалізувати / десеризувати, об'єкти документа будуть передаватися посиланням на клас "Документ" (або вказівником), і коли буде викликано метод "Серіалізація ()" або "Де-серіалізація ()". на ньому викликаються відповідні версії віртуальних методів.
Статичний (час компіляції) поліморфізм - це поліморфізм, виявлений під час компіляції. Тут компілятор Java знає, який метод викликається. Перевантаження методів та переосмислення методів за допомогою статичних методів; прийоми для статичного поліморфізму є методом переосмислення з використанням приватного або остаточного методів
Наприклад,
Об'єкт працівника може мати два способи print (), один не бере аргументів, а один приймає рядок з префіксом для відображення разом із даними працівника.
З огляду на ці інтерфейси, коли метод print () викликається без будь-яких аргументів, компілятор, дивлячись на аргументи функції, знає, яку функцію потрібно викликати, і відповідно генерує об'єктний код.
Більш детально читайте "Що таке поліморфізм" (Google це).
Прив'язка відноситься до зв'язку між викликом методу та визначенням методу.
На цій картині чітко видно, що є обов'язковим.
На цьому малюнку виклик "a1.methodOne ()" прив'язує до відповідного визначення methodOne (), а виклик "a1.methodTwo ()" прив'язує до відповідного визначення методуTwo ().
Для кожного виклику методу повинно бути відповідне визначення методу. Це правило в java. Якщо компілятор не бачить належного визначення методу для кожного виклику методу, він видає помилку.
Тепер переходимо до статичного зв'язування та динамічного зв’язування в java.
Статичне зв'язування на Java:
Статичне зв'язування - це зв'язування, яке відбувається під час компіляції. Його також називають ранньою прив'язкою, оскільки прив'язка відбувається до того, як програма фактично працює
.
Статичне зв'язування можна продемонструвати, як на малюнку нижче.
На цьому малюнку 'a1' є еталонною змінною типу класу A, що вказує на об'єкт класу A. 'a2' також є довідковою змінною класу типу A, але вказує на об'єкт класу B.
Під час компіляції, прив’язуючи, компілятор не перевіряє тип об'єкта, на який вказує певна довідкова змінна. Він просто перевіряє тип посилальної змінної, через яку викликається метод, і перевіряє, чи існує визначення методу для цього типу.
Наприклад, для виклику методу "a1.method ()" на малюнку вище, компілятор перевіряє, чи існує визначення методу для методу () у класі А. Оскільки "a1" - це клас класу. Аналогічно, для виклику методу "a2.method ()" він перевіряє, чи існує визначення методу для методу () у класі А. Оскільки "a2" також є класом типу A. Він не перевіряє, на який об’єкт вказують 'a1' та 'a2'. Цей тип зв'язування називається статичним зв'язуванням.
Динамічне зв'язування на Java:
Динамічне зв'язування - це зв'язування, яке відбувається під час виконання. Його також називають пізньою прив'язкою, оскільки прив'язка відбувається, коли програма насправді працює.
Під час виконання фактичні об'єкти використовуються для прив’язки. Наприклад, для виклику "a1.method ()" на наведеному вище зображенні буде викликаний метод () фактичного об'єкта, на який вказує "a1". Для виклику "a2.method ()" буде викликано метод () фактичного об'єкта, на який вказує "a2". Цей тип зв'язування називається динамічним зв'язуванням.
Динамічне зв'язування вищевказаного прикладу можна продемонструвати як нижче.
Посилання на статичне зв'язування та динамічне зв'язування в яві
Поліморфізм: Поліморфізм - це здатність об'єкта набувати багатьох форм. Найбільш поширене використання поліморфізму в ООП відбувається, коли посилання на батьківський клас використовується для позначення дочірнього об'єкта класу.
Поліморфізм динамічного зв’язування / виконання:
Час виконання Поліморфізм також відомий як метод перекриття. У цьому Механізмі, за допомогою якого виклик переосмисленої функції вирішується під час виконання.
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
{
}
}
У цьому прикладі людина має метод їжі, який означає, що він може їсти піцу або локшину. Що метод eat перевантажений, коли ми компілюємо цю Person.java, компілятор вирішує виклик методу "e.eat (локшина) [що знаходиться в рядку 6] із визначенням методу, зазначеним у рядку 8, тобто це метод, який приймає локшину як параметр і весь процес виконується компілятором, тож це поліморфізм часу компіляції. Процес заміни виклику методу визначенням методу називається обов'язковим, в цьому випадку це робиться компілятором, тому його називають ранньою зв'язуванням.
Виходячи з відповіді Нареша, динамічний поліморфізм у Java лише "динамічний" через наявність віртуальної машини та її здатності інтерпретувати код під час виконання, а не коду, що працює на самому світі.
У C ++ він повинен бути вирішений під час компіляції, якщо він компілюється до нативного бінарного файлу за допомогою gcc, очевидно; проте стрибок та скорочення часу виконання у віртуальній таблиці все ще називають "пошуком" або "динамічним". Якщо C успадковує B, а ви заявляєте 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()
, c буде вказувати вже на зовнішній об'єкт C, а покажчик буде переданий на C :: method1 () у текстовому сегменті. Зверніться до: http://www.programmersought.com/article/2572545946/
У Java, для B b = new C(); b.method1();
, віртуальна машина здатна динамічно перевіряти тип об'єкта в парі з b і може передавати правильний покажчик і викликати правильний метод. Додатковий крок віртуальної машини виключає потребу у віртуальних таблицях функцій або типі, який вирішується під час компіляції, навіть коли це могло бути відомо під час компіляції. Це просто інший спосіб зробити це, що має сенс, коли задіяна віртуальна машина, а код збирається лише в байт-код.