Спадковість. Перевизначення та перевантаження успадкованих методів. Ключове слово super. Приклади. Динамічна диспетчеризація методів. Поліморфізм
Зміст
- 1. Що таке перевизначення методу?
- 2. Яка відмінність між перевизначенням та перевантаженням методу?
- 3. Правило взаємодії між методами суперкласу та підкласу, які мають однакові імена та сигнатуру. Приклад
- 4. Отримання доступу з методу підкласу до методу суперкласу у випадку, якщо співпадають імена методів та сигнатури їх параметрів. Приклад
- 5. Приклад, що демонструє перевантаження методів у класах що утворюють ієрархію спадковості
- 6. Що таке динамічна диспетчеризація методів? Приклад реалізації поліморфізму в Java
- 7. Приклад, що демонструє способи реалізації поліморфізму (динамічної диспетчеризації методів)
- Зв’язані теми
Пошук на інших ресурсах:
1. Що таке перевизначення методу?
Перевизначення методу – це випадок, коли підклас та суперклас містять методи, які мають однакове ім’я та сигнатуру типів (рисунок 1). Перевизначення методу виникає коли класи утворюють ієрархію спадковості.
Рисунок 1. Приклад перевизначення методу method() суперкласу A в підкласі B
На рисунку 1 клас B успадковує (розширює) клас A. Клас A є суперкласом для класу B. У підкласі B оголошується метод з таким самим іменем як і в суперкласі A. Отже, у даному випадку, метод з іменем method() суперкласу A є перевизначеним у підкласі B.
⇑
2. Яка відмінність між перевизначенням та перевантаженням методу?
В ієрархії успадкування методи суперкласів та підкласів можуть бути перевизначеними та перевантаженими.
Між перевизначенням та перевантаженням методу є наступна відмінність:
- при перевизначенні методи суперкласу та підкласу мають однакове ім’я та однакову сигнатуру типів параметрів (див. рис. 1);
- при перевантаженні методи суперкласу та підкласу мають однакове ім’я але різні сигнатури типів параметрів. На рисунку 2 продемонстровано перевентаження методу в ієрархії успадкування.
Рисунок 2. Приклад перевантаження методу з іменем method() у класах A, B, C які утворюють ієрархію
На рисунку 2 зображено 3 класи з іменами A, B, C які утворюють ієрархію успадкування. Клас B успадковує клас A. Клас C успадковує клас B. У всіх класах реалізовано різні методи, які мають однакове ім’я method(). Параметри методу в кожному класі відрізняються. Це означає, що метод method() є перевантажений.
⇑
3. Правило взаємодії між методами суперкласу та підкласу, які мають однакові імена та сигнатуру. Приклад
Якщо в суперкласі та підкласі реалізовано методи, що мають однакове ім’я та сигнатуру типів параметрів, то діє наступне правило:
- метод з підкласу перевизначає метод суперкласу.
На рисунку 3 схематично зображено правило взаємодії між однойменними методами суперкласу та підкласу.
Рисунок 3. Демонстрація перевизначення методу суперкласу в методі підкласу
На рисунку 3 зображено приклад перевизначення методу суперкласу в підкласі. Оголошується 3 класи з іменами A, B, C. У кожному класі реалізовано метод з іменем method() який не отримує параметрів. Цей метод має однакову сигнатуру у всіх класах.
Кожен об’єкт (екземпляр) класу викликає метод класу на який він був оголошений. З екземпляру класу objB викликається метод method() який реалізований в класі B. З екземпляру класу objC викликається метод method(), що реалізований в класі C.
Нижче наведено текст програми що демонструє перевизначення методів, зображених на рисунку 3.
// суперклас class A { void method() { // метод класу A System.out.println("Method A"); } } // підклас класу A class B extends A { void method() { // метод класу B System.out.println("Method B"); } } // підклас класу B class C extends B { void method() { // метод класу C System.out.println("Method C"); } } public class Train01 { public static void main(String[] args) { A objA = new A(); B objB = new B(); C objC = new C(); objA.method(); // викликати method() класу A objB.method(); // викликати method() класу B objC.method(); // викликати method() класу C } }
Результат виконання програми
Method A Method B Method C
⇑
4. Отримання доступу з методу підкласу до методу суперкласу у випадку, якщо співпадають імена методів та сигнатури їх параметрів. Приклад
Інколи потрібно отримати доступ з методу підкласу до методу суперкласу, який має таке саме ім’я та сигнатуру параметрів. У цьому випадку використовується ключове слово super.
На рисунку 4 зображено доступ до методу суперкласу A з підкласу B. У підкласі B є метод з таким самим іменем та списком параметрів, тому, цей метод перевизначає метод суперкласу. Щоб доступитись до методу суперкласу A у методі підкласу B використовується ключове слово super.
Рисунок 4. Виклик методу суперкласу з методу підкласу з допомогою ключового слова super
Текст програми, що демонструє рисунок 4 наступний
// суперклас class A { void method() { // метод класу A System.out.println("Method A"); } } // підклас класу A class B extends A { void method() { // метод класу B System.out.println("Method B"); } void method2() { System.out.println("Method2 - B"); super.method(); // виклик методу суперкласу A } } public class Train01 { public static void main(String[] args) { B objB = new B(); // екземпляр класу B objB.method2(); } }
Результат виконання програми
Method2 - B Method A
⇑
5. Приклад, що демонструє перевантаження методів у класах що утворюють ієрархію спадковості
Якщо класи утворюють ієрархію шляхом успадкування, то у цих класах імена методів можуть співпадати.
Метод вважається перевантаженим (не перевизначеним) у випадку, якщо:
- в різних класах існує метод з таким самим іменем;
- сигнатура параметрів методу у кожному класі відрізняється.
Таким чином, методи з різними сигнатурами вважаються перевантаженими а не перевизначеними.
На рисунку 5 зображено приклад перевантаження методу з іменем method(). Оголошуються три класи з іменами A, B, C які утворюють ієрархію. У класі A метод з іменем method() реалізований без параметрів. У класі B метод з іменем method() реалізований з одним параметром типу int. У класі C метод з іменем method() реалізований з одним параметром типу double.
Рисунок 5. Перевантаження методу з іменем method() у класах, що утворюють ієрархію
Текст програми, що демонструє рисунок 5 наступний
// суперклас class A { void method() { // метод класу A System.out.println("Class A. Method without parameters."); } } // підклас класу A class B extends A { void method(int t) { // метод класу B System.out.println("Class B. Method with 1 parameter of type int: "+t); } } // підклас класу B class C extends B { void method(double x) { // метод класу C System.out.println("Class C. Method with 1 parameter of type double: "+x); } } public class Train01 { public static void main(String[] args) { C objC = new C(); // екземпляр класу C objC.method(); // виклик методу без параметрів класу A objC.method(5); // виклик методу класу B objC.method(9.75); // виклик методу класу C } }
Результат роботи програми
Class A. Method without parameters. Class B. Method with 1 parameter of type int: 5 Class C. Method with 1 parameter of type double: 9.75
⇑
6. Що таке динамічна диспетчеризація методів? Приклад реалізації поліморфізму в Java
Динамічна диспетчеризація методів є один з найбільш ефективних принципів об’єктно-орієнтованого програмування.
Динамічна диспетчеризація методів – це спеціальний механізм, який дозволяє викликати перевизначений метод в процесі виконання програми а не під час компіляції. Динамічна диспетчеризація методів важлива при реалізації поліморфізму.
Рисунок 6 демонструє динамічну диспетчеризацію методів. Реалізовано 3 класи з іменами A, B, C які утворюють ієрархію. У класах реалізовано метод з іменем method(). Сигнатура методу у всіх класах однакова.
Рисунок 6. Демонстрація динамічної диспетчеризації методів для трьох класів, що утворюють ієрархію
На початку коду демонстрації (рисунок 6) оголошується посилання refA на базовий клас A
A refA;
Після оголошення цьому посиланню можна присвоювати значення посилання на підклас класу A.
Таким чином, з допомогою посилання refA можна викликати методи класів A, B, C що утворюють ієрархію. Якщо refA посилається на екземпляр класу A, то рядок
refA.method();
буде викликати метод з іменем method() класу A.
Аналогічно, якщо посилання refA посилається на екземпляр (об’єкт) класу B, то
refA.method();
буде викликати відповідний метод класу B.
Те саме стосується і класу C.
Як видно з рисунку 6, відповідний варіант методу method() визначається типом об’єкту, на який посилається посилання refA, а не типом цього посилання в момент його оголошення.
Нижче наведено програмний код, що демонструє динамічну диспетчеризацію методів, зображену на рисунку 6.
// суперклас class A { void method() { // метод класу A System.out.println("Class A"); } } // підклас класу A class B extends A { void method() { // метод класу B System.out.println("Class B"); } } // підклас класу B class C extends B { void method() { // метод класу C System.out.println("Class C"); } } public class Train01 { public static void main(String[] args) { // екземпляри класів A, B, C A objA = new A(); B objB = new B(); C objC = new C(); // посилання на суперклас A A refA; // посиланню refA можна присвоїти objA, objB, objC refA = objA; // refA посилається на екземпляр класу A refA.method(); // виклик методу method() класу A // refA = objB; // refA -> objB refA.method(); // objB.method() // refA = objC; // refA -> objC refA.method(); // objC.method() } }
Результат виконання програми
Class A Class B Class C
⇑
7. Приклад, що демонструє способи реалізації поліморфізму (динамічної диспетчеризації методів)
Поліморфізм може бути реалізований у програмах двома способами:
- при присвоєнні (=) посиланню на базовий клас екземпляру будь-якого похідного класу. У цьому випадку з допомогою посилання (через символ ‘.‘) викликається перевизначений метод того екземпляру, на який на даний момент вказує це посилання;
- при реалізації деякого методу, який отримує параметром посилання на базовий клас. У цьому випадку, в тілі методу викликається перевизначений метод (метод, що має спільне ім’я та сигнатуру в усіх класах ієрархії) за посиланням. Від того, на екземпляр якого класу вказує посилання, залежить який саме перевизначений метод буде викликано.
Нижченаведений приклад демонструє ці два випадки на прикладі ієрархії з трьох класів A, B, C. Усі класи мають метод Print() без параметрів.
// Деяка ієрархія класів. // Всі класи мають метод Print(). class A { public void Print() { System.out.println("A.Print()"); } } class B extends A { public void Print() { System.out.println("B.Print()"); } } class C extends B { public void Print() { System.out.println("C.Print()"); } } public class TrainPoymorphism { // Метод, що отримує посилання на базовий клас A public static void CallPrint(A ref) { // за посиланням викликати метод Print() деякого класу з ієрархії ref.Print(); } public static void main(String[] args) { // Демонстрація поліморфізму на прикладі передачі // параметру в метод CallPrint() // 1. Створити екземпляри класів A, B, C A objA = new A(); B objB = new B(); C objC = new C(); // 2. Створити посилання на базовий клас в ієрархії A <- B <- C A refA; // 3. Демонстрація поліморфізму // 3.1. Демонстрація поліморфізму через присвоєння = refA = objA; // refA -> objA refA.Print(); // A.Print() refA = objB; // refA -> objB refA.Print(); // B.Print() refA = objC; // refA -> objC refA.Print(); // C.Print() System.out.println("-------------------"); // 3.2. Демонстрація поліморфізму через передачу // посилання на базовий клас в метод CallPrint(A ref) refA = objA; // refA -> objA CallPrint(refA); // A.Print() refA = objB; // refA -> objB CallPrint(refA); // B.Print() refA = objC; // refA -> objC CallPrint(refA); // C.Print() } }
Результат виконання програми
A.Print() B.Print() C.Print() ------------------- A.Print() B.Print() C.Print()
⇑
Зв’язані теми
- Повторне використання коду в класах. Поняття композиції, спадковості, делегування. Ключове слово extends. Приклади
- Спадковість. Основні поняття. Суперклас та підклас. Ключове слово extends. Приховування даних в успадкованих класах. Модифікатори доступу private, protected, public
- Спадковість. Посилання на об’єкт підкласу. Виклик конструктора суперкласу. Ключове слово super
⇑