Переопределение методов в Java

🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!

Наверняка вы сталкивались с ситуацией, когда в одном классе несколько методов с одинаковым названием, но с разными параметрами. В таких случаях можно применить перегрузку методов.

В этой статье будет рассмотрена другая ситуация. Представьте, что есть один общий метод, но в зависимости от класса он должен выполнять разные действия.

Как это реализовать?

Чтобы разобраться, создадим родительский класс Animal, который будет представлять животных, и добавим в него метод speak:

public class Animal {

   public void speak() {

       System.out.println("Hello!");
   }
}
Run Code

Несмотря на то, что мы только начали писать программу, вы скорее всего уже заметили потенциальную проблему: в мире существует множество животных, и они все “говорят” по-разному: кошки мяукают, утки крякают, а змеи шипят.

Цель очевидна: не писать отдельные методы для каждого звука. Вместо того чтобы создавать catSpeak() для кошки, snakeSpeak() для змеи и так далее, мы хотим вызвать speak(), чтобы змея шипела, кошка мяукала, а собака лаяла.

Добиться этого можно с помощью переопределения методов.

Википедия объясняет термин «переопределение» («overriding») следующим образом: Переопределение методов в объектно-ориентированном программировании — это механизм, позволяющий подклассу (дочернему классу) задать свою реализацию метода, унаследованного от родительского класса (суперкласса).

По сути, это верно. Переопределение методов позволяет взять метод родительского класса и написать для него собственную реализацию в каждом дочернем классе. Новая реализация “заменяет” реализацию родительского класса в дочернем.

Рассмотрим пример. Создадим 4 класса, которые наследуются от класса Animal:

public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
Run Code

Вот небольшой лайфхак на будущее: чтобы переопределить методы родительского класса, откройте код дочернего класса в IntelliJ IDEA, нажмите Ctrl + O и выберите “Override methods…” в меню. Использование горячих клавиш ускорит вашу работу!

Для реализации нужного поведения мы проделали следующие шаги:

  1. В каждом дочернем классе мы объявили метод с таким же именем, как у метода в родительском классе.
  2. Мы дали компилятору понять, что совпадение имен методов с родительским классом — не случайность: мы действительно хотим изменить их поведение. Для этого мы добавили аннотацию @Override над методом.
    Аннотация @Override сигнализирует компилятору (и программистам, которые будут читать код): «Всё в порядке. Это не ошибка. Я знаю, что такой метод уже есть, и намеренно его переопределяю».
  3. Мы задали нужное поведение для каждого класса. Теперь при вызове метода speak() змея будет шипеть, медведь — рычать и так далее.


Посмотрим, как это реализуется на практике:

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.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
Run Code

Что мы увидим в консоли:

Woof!
Meow!
Growl!
Hiss!

Отлично! Все работает так, как задумано! Мы создали 4 переменные-ссылки типа Animal и присвоили им объекты 4 разных подклассов.

Благодаря этому каждый объект демонстрирует свое поведение: в дочерних классах переопределенный метод speak() заменил стандартный метод speak() из Animal, который просто выводил “Hello!”.

Переопределение имеет несколько ограничений:

  1. Переопределенный метод должен иметь те же параметры, что и метод в родительском классе.

Если метод speak() в родительском классе принимает параметр типа String, то переопределенный метод в дочернем классе также должен принимать параметр типа String. В противном случае компилятор выведет ошибку:

public class Animal {

   public void speak(String s) {

       System.out.println("Hello! " + s);
   }
}

public class Cat extends Animal {

   @Override 
   public void speak() {
       System.out.println("Meow!");
   }
}
Run Code
  1. Переопределенный метод должен иметь тот же тип возвращаемого значения, что и метод родительского класса.

В противном случае компилятор выдаст ошибку:

public class Animal {

   public void speak() {

       System.out.println("Hello!");
   }
}


public class Cat extends Animal {

   @Override
   public String speak() {         
       System.out.println("Meow!");
       return "Meow!";
   }
}
Run Code
  1. Переопределенный метод должен иметь такой же модификатор доступа, как и исходный метод:
public class Animal {

      public void speak() {

            System.out.println("Hello!");
      }
}

public class Cat extends Animal {

       @Override
       private void speak() {      
           System.out.println("Meow!");
       }
}
Run Code

Переопределение методов в Java — это один из способов реализации полиморфизма (одного из принципов ООП).

Это значит, что основным преимуществом является гибкость. Мы можем создать простую и логичную систему классов, каждый из которых будет обладать своим поведением (собаки лают, кошки мяукают), с общим интерфейсом — одним методом speak() для всех, вместо множества методов, например, dogSpeak(), speakCat() и так далее.

Перевод статьи «Method Overriding in Java».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх