Что значит переопределение метода java

Перегрузка и переопределение методов в Java: примеры

Метод в Java — это функция, которая определяет, что умеет делать объект этого класса. Одна из главных задач методов — выполнение действий над данными объекта. Они могут менять значение, преобразовывать данные, выводить их в консоль.

Методы можно перегружать и переопределять. Как это делать и в чём разница между этими двумя механизмами — разберёмся в этой статье.

Перегрузка метода

Перегрузка методов в Java — это использование одного имени метода с разными параметрами.

Чтобы разобраться с этим механизмом, начнём с простого — создадим помощника, который будет здороваться с пользователями.

public class Assistant  
public void sayHello(String name) System.out.println("Добрый день, " + name + "!");
>

public static void main(String[] args) Assistant assistant = new Assistant();
assistant.sayHello("Михаил");
>
>

В консоли будет выведена фраза «Добрый день, Михаил!».

Допустим, Михаил пришёл не один, а с другом Виталием. Сейчас метод реализован так, что помощник поприветствует только Михаила, а Виталия проигнорирует. Чтобы исправить это, реализуем в классе два метода. Имя у них будет одинаковое. Но параметры они принимают разные.

public class Assistant  
public void sayHello(String firstGuest) System.out.println("Добрый вечер, " + firstGuest + "!");
>

public void sayHello(String firstGuest, String secondGuest) System.out.println("Добрый день, " + firstGuest + " и " + secondGuest + "!");
>
public static void main(String[] args) Assistant assistant = new Assistant();
assistant.sayHello("Михаил", "Виталий");
>
>

Теперь в консоли отобразится фраза «Добрый день, Михаил и Виталий!».

Мы уже перегрузили sayHello(). Теперь программа стала более гибкой — помощник может приветствовать сразу двух гостей. Но что произойдёт, если придут трое, четверо или пятеро? Проверим:

public class Assistant  
public void sayHello(String firstGuest) System.out.println("Добрый вечер, " + firstGuest + "!");
>

public void sayHello(String firstGuest, String secondGuest) System.out.println("Добрый день, " + firstGuest + " и " + secondGuest + "!");
>
public static void main(String[] args) Assistant assistant = new Assistant();
assistant.sayHello("Михаил", "Виталий", "Марина");
>
>

В ответ получим ошибку, потому что sayHello() готов принимать только два аргумента. Решение в лоб — перегружать его дальше. Сделать так, чтобы .sayHello() принимал троих, четверых, пятерых и больше гостей. Но это не похоже на гибкую работу программы. Придётся постоянно дописывать код.

Более гибкое решение — передать в качестве параметра аргумент переменной длины (String… names). Это позволит sayHello() принимать любое количество строк. А чтобы выводить в консоль приветствие каждого гостя, используем цикл.

public class Assistant  
public void sayHello(String firstGuest) System.out.println("Добрый вечер, " + firstGuest + "!");
>

public void sayHello(String… names)
for (String name: names) System.out.println("Добрый вечер, " + name + "!");
>
>

public static void main(String[] args) Assistant assistant = new Assistant();
assistant.sayHello("Михаил", "Виталий", "Марина", "Андрей", "Анна");
>

В консоли отобразится приветствие каждого переданного гостя:

Добрый вечер, Михаил!
Добрый вечер, Виталий!
Добрый вечер, Марина!
Добрый вечер, Андрей!
Добрый вечер, Анна!

Порядок аргументов

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

Но порядок аргументов имеет значение, если метод принимает, например, строку и число. Посмотрите:

public class User  
public static void sayYourAge(String greeting, int age) System.out.println(greeting + " " + age);
>

public static void main(String[] args) sayYourAge(20, "Мой возраст - "); //ошибка!
>
>

На этапе компиляции возникнет ошибка, потому что при определении sayYourAge() мы задали, что сначала должна быть строка, а затем — число, но аргументы передали в обратном порядке.

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

public class User  
public static void sayYourAge(String greeting, int age) System.out.println(greeting + " " + age);
>

public static void main(String[] args) sayYourAge("Мой возраст - ", 20);
>
>

Чтобы избежать ошибок, можно сделать перегрузку порядком параметров. Например, вот так:

public class User  
public static void sayYourAge(String greeting, int age) System.out.println(greeting + " " + age);
>
public static void sayYourAge(int age, String greeting) System.out.println(greeting + " " + age);
>

public static void main(String[] args) sayYourAge("Мой возраст - ", 20);
sayYourAge(20, "Мой возраст - ");
>
>

Теперь не имеет значения, в каком порядке передавать аргументы — оба варианты будут понятны программе.

Варианты перегрузки

Из примеров выше можно выделить три варианта перегрузки.

public class Calculator void calculate(int number1, int number2) < > 
void calculate(int number1, int number2, int number3) < >
>
public class Calculator void calculate(int number1, int number2) < > 
void calculate(double number1, double number2) < >
>
public class Calculator void calculate(double number1, int number2) < > 
void calculate(int number1, double number2) < >
>

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

Перегрузка — это часть полиморфизма, одной из ключевых составляющих объектно-ориентированного программирования. Главный плюс перегрузки в Java — можно использовать схожие методы с одинаковыми именами.

Переопределение метода

Переопределение метода в Java позволяет взять метод родительского класса и создать специфическую реализацию в классе-наследнике.

Проще понять на примере. Допустим, вы создаёте класс Animal с методом voice(). Он нужен для того, чтобы животное могло подать голос:

public class Animal  
public void voice()
System.out.println("Говори!");
>
>

И сразу возникает проблема — все животные издают разные звуки. Можно создать для каждого отдельный метод. Например, у кошки это будет voiceCat(), а у собаки — voiceDog(). Но представьте, сколько строк кода придётся написать, чтобы дать возможность всем животным подать голос?

Здесь на помощь и приходит механизм переопределения в Java. Он позволяет заменить реализацию в классе-наследнике. Посмотрим на примере кошки и собаки:

public class Cat extends Animal  
@Override
public void voice() System.out.println("Мяу!");
>
>

public class Dog extends Animal
@Override
public void voice() System.out.println("Гав!");
>
>

В выводе отобразится сначала «Мяу», а затем — «Гав». Чтобы добиться такого результата, нужно:

  1. В классе-наследнике создать метод с таким же именем, как в родительском классе.
  2. Добавить перед ним аннотацию @Override (с английского переводится как «переопределён»). Эта аннотация сообщит компилятору, что это не ошибка, вы намеренно переопределяете метод. Отметим, что наличие аннотации необязательно. Если в дочернем классе создать метод с такой же сигнатурой, как у родительского, метод все равно переопределится. Но рекомендуется ставить аннотацию всегда, так как это улучшает «читабельность» кода, а также при этом компилятор проверит на этапе сборки, что такой метод действительно есть в родительском классе.

Собственная реализация пишется для каждого класса-наследника. Если этого не сделать, то будет использована реализация родительского класса.

Даже после переопределения вы можете обратиться к методу родительского класса при условии, что он не определён модификатором private. Для этого используется ключевое слово super:

Ограничения при переопределении

У переопределения методов класса в Java есть ряд ограничений.

  • Название метода должно быть таким же, как у метода родителя (то есть сигнатура метода должна быть одинаковой).
  • Аргументы должны оставаться такими же, как у метода родителя.
  • Тип возвращаемого значения должен быть таким же, как у метода родителя.
  • Модификатор доступа должен быть таким же, как у метода родителя.
  • Окончательные методы (final) нельзя переопределять. Это один из способов запрета переопределения — объявить метод с помощью ключевого слова final.
class Parent final void show() <>
>

class Child extends Parent void show() <>
>

Такой код вернёт ошибку, потому что в родительском классе использовано ключевое слово final.

  • Статические методы (static) нельзя переопределять. Если вы определите в классе-наследнике такую же сигнатуру метода, как в родительском классе, то выполните сокрытие. Подробнее об этом вы можете прочитать в документации .
  • Приватные методы (private) нельзя переопределять, так как они связываются на этапе компиляции, а не выполнения.
  • Нельзя сужать модификатор доступа — например, с public до private. Расширение уровня доступа возможно.
  • Нельзя менять тип возвращаемого значения, однако можно сузить возвращаемое значение, если они совместимы.

Переопределение класса в Java подчиняется указанным выше правилам, которые необходимо соблюдать.

Собственные правила переопределения есть у отдельных методов. Например, equals() и hashCode(). Самое важное условие — если вы переопределяете equals(), то должны переопределить и hashCode(). В противном случае классы и методы, которые пользуются контрактами стандартной реализации этих двух методов, могут работать с ошибками. Подробнее от этом мы рассказали в отдельной статье.

Заключение

Переопределение и перегрузка методов в Java — важные части полиморфизма, однако это разные механизмы. При перегрузке вы создаёте внутри одного класса много методов с одинаковым названием, но разными параметрами. При переопределении вы берёте один и тот же метод и заставляете его делать разные вещи в зависимости от того, в каком классе его вызвали.

Но есть характеристики, в которых перегрузка и переопределение Java похожи. Оба механизма помогают сделать код чище и читабельнее, а также уменьшить количество ошибок при выполнении программ.

Источник

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

Привет! Это статья про переопределение (override) методов в Java. Она тесно связана с пониманием принципов ООП, классов и механизма наследования. Если Вы плохо разбираетесь в этих темах, сначала почитайте:

Что такое переопределение в Java

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

И вот в этот момент — момент наследования — может возникнуть проблема. Чтобы проиллюстрировать, представим, что у нас есть класс Animal. Этот класс имеет несколько методов — в том числе и метод voice() («голос»):

Давайте теперь представим, что мы создаем класс Cat, который наследует Animal:

Но сейчас если мы создадим кошку и запустим метод voice() , мы получим «This is my voice!». Например, если запустим это:

Как мы знаем, кошка не говорит «This is my voice!» 🙂 Кошка мяукает, собака лает, и т.д.

Таким образом, мы хотели бы, чтобы при вызове метода voice() наша кошка говорила «Мяу». Конечно, мы можем создать новый метод — например, catVoice(), — но это было бы не очень эффективно. Что, если мы хотим изменить 3, 5 или 10 методов? И что, метод родителя будет лежать у нас мертвым грузом?

Нет, нам совершенно не обязательно идти этим путем. Гораздо лучше, если мы просто будем иметь «свой вариант» нужного метода. Мы можем сделать так, чтобы нам не надо было менять название или параметры метода, но он вызвал нужный нам результат. Для этого мы просто должны переопределить метод родителя.

Как нам переопределить метод voice()? Все очень просто:

  • Во-первых, мы заново прописываем метод voice() в нашем классе Cat
  • Во-вторых, мы должны дать Java понять, что мы не ошиблись и не назвали метод названием, которое уже есть, из-за невнимательности. Чтобы сказать, что мы знаем, что делаем и действительно хотим переопределить(по англ. «override«) метод, нужно над методом написать @Override .

В коде, например, это выглядит так:

Источник

Читайте также:  Обратная связь
Оцените статью