🔥 🚀 Важно для всех, кто работает с 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…” в меню. Использование горячих клавиш ускорит вашу работу!
Для реализации нужного поведения мы проделали следующие шаги:
- В каждом дочернем классе мы объявили метод с таким же именем, как у метода в родительском классе.
- Мы дали компилятору понять, что совпадение имен методов с родительским классом — не случайность: мы действительно хотим изменить их поведение. Для этого мы добавили аннотацию
@Override
над методом.
Аннотация@Override
сигнализирует компилятору (и программистам, которые будут читать код): «Всё в порядке. Это не ошибка. Я знаю, что такой метод уже есть, и намеренно его переопределяю». - Мы задали нужное поведение для каждого класса. Теперь при вызове метода
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!”.

Переопределение имеет несколько ограничений:
- Переопределенный метод должен иметь те же параметры, что и метод в родительском классе.
Если метод 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- Переопределенный метод должен иметь тот же тип возвращаемого значения, что и метод родительского класса.
В противном случае компилятор выдаст ошибку:
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- Переопределенный метод должен иметь такой же модификатор доступа, как и исходный метод:
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».