JavaRush /Java блог /Random UA /Механізм перевизначення методів або Override у Java

Механізм перевизначення методів або Override у Java

Стаття з групи Random UA
Вітання! Ти вже використовуєш методи Java і знаєш про них багато чого. Напевно, ти стикався з ситуацією, коли в одному класі було багато методів з однаковою назвою, але різними аргументами. Якщо пам'ятаєш, тоді ми використовували механізм перевантаження методів. Сьогодні розглянемо іншу ситуацію. Уяви, що у нас є один загальний метод, але він повинен робити різні речі, залежно від того, в якому класі він був викликаний. Як реалізувати таку поведінку? Щоб розібратися, візьмемо батьківський клас Animal, що означає тварин, і створимо в ньому метод voice- " голос ":
public class Animal {

   public void voice() {

       System.out.println("Голос!");
   }
}
Хоча ми тільки почали писати програму, потенційна проблема тобі, швидше за все, видно: тварин у світі дуже багато, і всі «говорять» по-різному: кішки нявкають, качки крякають, змії шиплять. Як влаштований механізм перевизначення методів. Наша мета проста: уникнути створення купи методів для голосування. Замість того, щоб створювати методи voiceCat()для м'якання, voiceSnake()для шипіння і т.д., ми хочемо, щоб при виклику методу voice()змія шипіла, кішка мяукала, а собака гавкала. Ми легко досягнемо цього за допомогою механізму перевизначення методів (Override у Java) . Вікіпедія дає таке пояснення терміна «перевизначення»: Перевизначення методу (англ. Method overriding)) в об'єктно-орієнтованому програмуванні - одна з можливостей мови програмування, що дозволяє підкласу або дочірньому класу забезпечувати специфічну реалізацію методу, вже реалізованого в одному із суперкласів або батьківських класів. Воно, загалом, правильне. Перевизначення дозволяє взяти якийсь метод батьківського класу та написати у кожному класі-спадкоємці свою реалізацію цього методу. Нова реалізація замінить батьківську в дочірньому класі. Розглянемо, як це на прикладі. Створимо 4 класи-спадкоємці для нашого класу Animal:
public class Bear extends Animal {
   @Override
   public void voice() {
       System.out.println("Р-р-р!");
   }
}
public class Cat extends Animal {

   @Override
   public void voice() {
       System.out.println("Мяу!");
   }
}

public class Dog extends Animal {

   @Override
   public void voice() {
       System.out.println("Гав!");
   }
}


public class Snake extends Animal {

   @Override
   public void voice() {
       System.out.println("Ш-ш-ш!");
   }
}
Невеликий лайфхак на майбутнє: щоб перевизначити методи батьківського класу, перейди в код класу-спадкоємця в Intellij IDE a, натисніть Ctrl+O та вибери в меню " Override methods... ". Звикай користуватись гарячими клавішами з початку, це прискорює написання програм! Щоб поставити потрібну нам поведінку, ми зробабо кілька речей:
  1. Створабо в кожному класі-спадкоємці метод з такою самою назвою, як і у методу батьківського класу.
  2. Повідомабо компілятору, що ми не просто так назвали метод так само, як у класі-батьку: хочемо перевизначити його поведінку. Для цього «повідомлення» компілятор ми поставабо над методом анотацію @Override («перевизначений»).
    Проставлена ​​над методом анотація @Override повідомляє компілятору (та й програмістам, що читають твій код теж): «Все ок, це не помилка і не моя забудькуватість. Я пам'ятаю, що такий метод вже є, і хочу його перевизначити».

  3. Написали потрібну нам реалізацію для кожного класу-нащадка. Змія при виклику voice()повинна шипіти, ведмідь - гарчати і т.д.
Давай подивимося, як це працюватиме у програмі:
public class Main {

   public static void main(String[] args) {

       Animal animal1 = new Dog();
       Animal animal2 = new Cat();
       Animal animal3 = new Bear();
       Animal animal4 = new Snake();

       animal1.voice();
       animal2.voice();
       animal3.voice();
       animal4.voice();
   }
}
Висновок у консоль: Гав! Мяу! Р-р-р! Ш-ш-ш! Добре, все працює як треба! Ми створабо 4 змінні-посилання батьківського класу Animal, і привласнабо їм 4 різних об'єкти класів-спадкоємців. У результаті кожен об'єкт поводиться по-своєму. Для кожного з класів-спадкоємців перевизначений метод voice()замінив «рідний» метод voice()із класу Animal(який виводить у консоль просто «Голос!»). Як влаштований механізм перевизначення методів. У перевизначення є низка обмежень:
  1. У перевизначеного методу мають бути самі аргументи, як і в методу батька.

    Якщо метод voiceбатьківського класу приймає на вхід String, перевизначений метод у класі-нащадку теж повинен приймати на вхід String, інакше компілятор видасть помилку:

    public class Animal {
    
       public void voice(String s) {
    
           System.out.println("Голос!" + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override//помилка!
       public void voice() {
           System.out.println("Мяу!");
       }
    }

  2. У перевизначеного методу має бути той самий тип значення, що повертається, що і у методу батька.

    В іншому випадку ми отримаємо помилку компіляції:

    public class Animal {
    
       public void voice() {
    
           System.out.println("Голос!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String voice() {         //помилка!
           System.out.println("Мяу!");
           return "Мяу!";
       }
    }

  3. Модифікатор доступу у перевизначеного методу також не може відрізнятись від «оригінального»:

    public class Animal {
    
       public void voice() {
    
           System.out.println("Голос!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void voice() {      //помилка!
           System.out.println("Мяу!");
       }
    }
Перевизначення методів Java — один із інструментів для реалізації ідеї поліморфізму (принципу ООП, про який ми розповідали в минулій лекції). Тому головною перевагою його використання буде та сама гнучкість, про яку ми говорабо раніше. Ми можемо побудувати просту і логічну систему класів, кожен з яких матиме специфічну поведінку (собаки гавкають, кішки нявкають), але єдиним інтерфейсом — один метод voice()на всіх замість купи методів voiceDog(), voiceCat()і т.д.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ