JavaRush /Курси /Java Syntax Zero /Успадкування

Успадкування

Java Syntax Zero
Рівень 8 , Лекція 7
Відкрита

1. Пегас

Розгляньмо детальніше третій принцип ООПуспадкування. Це дуже цікаве питання, з яким ви часто стикатиметеся. На думку необізнаних, програмування — це якась магія. Тому почнімо з отакої цікавої аналогії…

Припустімо, що ви — чарівник і хочете створити крилатого коня. Можна спробувати просто начаклувати такого пегаса. Але оскільки пегасів в природі не існує, це буде досить складно. Доведеться дуже багато робити з нуля. Куди простіше взяти коня й дочаклувати йому крила.

Успадкування. ООП

У програмуванні такий процес називається «успадкуванням». Припустімо, вам потрібно написати дуже складний клас. Писати з нуля довго, потім доведеться все тестувати й шукати помилки. То навіщо йти найскладнішим шляхом? Краще пошукати, а чи немає десь такого класу?

Припустімо, ви знайшли клас, який своїми методами реалізує 80 % потрібної вам функціональності. Що робити з ним далі? Ви можете просто скопіювати його код у свій клас. Однак такий спосіб має кілька мінусів:

  1. Знайдений клас уже може бути скомпільовано в байт-код, а доступу до його вихідного коду у вас немає.
  2. Вихідний код класу є, але ви працюєте в компанії, яку можуть засудити на пару мільярдів за використання навіть 6 рядків чужого коду. А потім вона засудить вас.
  3. Непотрібне дублювання великого обсягу коду. Крім того, автор чужого класу може знайти в ньому помилку й виправити її. А у вас ця помилка залишиться.

Є кращий спосіб, який не потребує легального доступу до коду вихідного класу. У мові Java можна просто оголосити потрібний клас батьківським для вашого класу. Ви отримаєте такий самий результат, наче ви додали код цього класу в код свого. У вашому класі з'являться всі дані та всі методи батьківського класу. Наприклад, можна зробити так: успадковуємо клас від «коня», додаємо «крила» й отримуємо «пегаса».


2. Спільний базовий клас

Успадкування можна також використовувати для інших цілей. Припустімо, у вас є десять класів, які дуже схожі між собою, мають багато однакових даних і методів. Ви можете створити спеціальний базовий клас, винести однакові дані (і методи, які з ними працюють) у цей базовий клас і оголосити ті десять класів його спадкоємцями. Тобто вказати в кожному класі, що у нього є батьківський клас — цей базовий клас.

Так само, як переваги абстракції розкриваються лише в поєднанні з інкапсуляцією, так і переваги успадкування значно збільшуються в разі використання поліморфізму. Однак про це ви дізнаєтеся трохи згодом. А сьогодні ми розглянемо кілька прикладів використання успадкування.

Шахові фігури

Припустімо, ми пишемо програму, що грає в шахи з користувачем, тож нам знадобляться класи для фігур. Які ж це будуть класи?

Якщо ви коли-небудь грали в шахи, то відповідь очевидна: Король, Ферзь, Слон, Кінь, Тура й Пішак.

До того ж у цих класах потрібно зберігати інформацію щодо кожної фігури. Наприклад, координати x і y, а також цінність фігури. Адже деякі фігури цінніші за інших.

Крім того, фігури здійснюють ходи по-різному, тож і поведінка класів має відрізнятися. Отак їх можна описати у вигляді класів:

class King
{
   int x;
 int y;
   int worth;

   void kingMove()
   {
     // код, що вирішує,
     // який хід зробить
     // король
   }
}
class Queen
{
   int x;
   int y;
   int worth;

   void queenMove()
   {
     // код, що вирішує,
     // який хід зробить
     // ферзь
   }
}
class Rook
{
   int x;
   int y;
   int worth;

   void rookMove()
   {
     // код, що вирішує,
     // який хід зробить
     // тура
   }
}
class Knight
{
   int x;
   int y;
   int worth;

   void knightMove()
   {
     // код, що вирішує,
     // який хід зробить
     // кінь
   }
}
class Bishop
{
   int x;
 int y;    int worth;

   void bishopMove()
   {
     // код, що вирішує,
     // який хід зробить
     // слон
   }
}
class Pawn
{
   int x;
   int y;
   int worth;

   void pawnMove()
   {
     // код, що вирішує,
     // який хід зробить
     // пішак
   }
}

Це дуже примітивний опис шахових фігур.

Спільний базовий клас

За допомогою успадкування цей код можна скоротити. Однакові методи й дані можна винести у спільний клас. Назвемо його ChessItem. Об'єкти класу ChessItem не має сенсу створювати, оскільки йому не відповідає жодна шахова фігура, але він дуже корисний:

class King extends ChessItem
{
   void kingMove()
   {
     // код, що вирішує,
     // який хід зробить король
   }
}
class Queen extends ChessItem
{
   void queenMove()
   {
     // код, що вирішує,
     // який хід зробить ферзь
   }
}
class Rook extends ChessItem
{
   void rookMove()
   {
     // код, що вирішує,
     // який хід зробить тура
   }
}
class ChessItem
{
   int x;
   int y;
   int worth;
}
class Knight extends ChessItem
{
   void knightMove()
   {
     // код, що вирішує,
     // який хід зробить кінь
   }
}
class Bishop extends ChessItem
{
   void bishopMove()
   {
     // код, що вирішує,
     // який хід зробить слон
   }
}
class Pawn extends ChessItem
{
   void pawnMove()
   {
     // код, що вирішує,
     // який хід зробить пішак
   }
}

Це чудовий спосіб спростити код схожих об'єктів. Найбільше переваг ми отримуємо, коли проєкт містить тисячі різних об'єктів і сотні класів. Тоді правильний підбір батьківських (базових) класів дає змогу не тільки істотно спростити логіку, але й скоротити код у десятки разів.


3. Успадкування класу — extends

То що ж потрібно, щоб успадкувати якийсь клас? Щоб успадкувати один клас від іншого, потрібно після оголошення нашого класу вказати ключове слово extends та ім'я батьківського класу. Зазвичай це має приблизно такий вигляд:

class Нащадок extends Батько

Саме таку конструкцію слід написати під час оголошення класу «Нащадок». До речі, успадкування можливе тільки від одного класу.

Успадкування класу — extends

На малюнку ми бачимо «корову», успадковану від «свині». «Свиню» успадковано від «курки», а «курку» — від «яйця». Тільки один батько! Таке успадкування не завжди логічне. Але якщо є тільки свиня, а дуже потрібна корова, програміст часто не здатний встояти перед спокусою зробити «корову» зі «свині».

У мові Java відсутнє множинне успадкування: не можна успадкувати клас від двох класів. У кожного класу може бути лише один батьківський клас. Якщо батьківський клас не вказано, ним вважається клас Object.

Натомість у Java є множинне успадкування інтерфейсів. Це трохи знижує гостроту проблеми. Про інтерфейси ми поговоримо трохи згодом, а поки що продовжимо розгляд успадкування.

P.S.

Отут ви знайдете кілька історій про те, як часто доводиться робити з мухи свиню. І якими можуть бути наслідки:


Коментарі (8)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Potapchuk Рівень 13
4 вересня 2023
Посилання https://voron-vp.livejournal.com/42033.html - НЕ ПРАЦЮЄ!!! =(
Sava_crosava Рівень 23
12 вересня 2023
На жаль, цей сервіс попав під блокування) Стаття досить цікава, тому використай англомовний контент або ж юзай VPN(
Валерій Рівень 41
13 лютого 2025
працює через VPN
Vitalii Рівень 11
10 серпня 2023
нащо вони в кожній фігурі в назві метода додатково пишуть назву класа? це типу для тих що з першого разу не розуміє? Якщо він напише king.kingMove() то приходить якось краще?
Саша Рівень 30
2 жовтня 2022
Чому правильна відповідь не виконує завдання? Перечитував все, але присвоєння класу не найшов
Roma Chernesh Рівень 16
20 грудня 2022
Та нормально все працює) Хіба довчився би хтось до 16 рівня, якби тут все так погано було? :)
Mykola Рівень 15 Expert
8 серпня 2023
Roma Chernesh, Закинув?
Julia Рівень 17
14 грудня 2024
Mykola, закинув?)