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


Переопределение

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

Преимущество переопределения заключается в том, что подкласс может по мере необходимости определять поведение, специфичное для себя. То есть подкласс может реализовать метод родительского класса по мере необходимости. Таким образом, когда для вызова метода используется объект подкласса, выполняется метод в подклассе, а не метод в родительском классе.

Переопределяющий метод не может выбрасывать новые проверяемые исключения или исключения более широкие, чем объявленные переопределяемым методом. Например: метод в родительском классе объявляет проверяемое исключение IOException, но при переопределении этого метода нельзя выбрасывать Exception, потому что Exception является родительским классом для IOException. Можно выбрасывать IOException или исключение подкласса IOException.

В объектно-ориентированных принципах переопределение означает, что любой существующий метод может быть переопределён. Вот пример:

Код файла TestDog.java:

class Animal{ public void move(){ System.out.println("Животные могут двигаться"); } } class Dog extends Animal{ public void move(){ System.out.println("Собаки могут бегать и ходить"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); //объект Animal Animal b = new Dog(); //объект Dog a.move();//Выполнить метод класса Animal b.move();//Выполнить метод класса Dog } }

Результат компиляции и выполнения вышеприведённого примера следующий:

Animals can move
Dogs can run and walk

В приведенном выше примере видно, что хотя b имеет тип Animal, он выполняет метод move класса Dog.

Это потому, что на этапе компиляции проверяется только ссылочный тип параметра.

Однако во время выполнения виртуальная машина Java (JVM) определяет тип объекта и выполняет метод объекта.

Следовательно, в приведенном выше примере компиляция проходит успешно, потому что класс Animal имеет метод move; однако во время выполнения выполняется метод конкретного объекта.

Рассмотрим следующий пример:

Код файла TestDog.java:

class Animal{ public void move(){ System.out.println("Животные могут двигаться"); } } class Dog extends Animal{ public void move(){ System.out.println("Собаки могут бегать и ходить"); } public void bark(){ System.out.println("Dogs can bark"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); //объект Animal Animal b = new Dog(); //объект Dog a.move();//Выполнить метод класса Animal b.move();//Выполнить метод класса Dog b.bark(); } }

Результат компиляции и выполнения вышеприведённого примера следующий:

TestDog.java:30: cannot find symbol
symbol  : method bark()
location: class Animal
                b.bark();
                 ^

Программа выдаст ошибку компиляции, потому что у ссылочного типа b, Animal, нет метода bark.


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

  • Список параметров должен быть точно таким же, как список параметров переопределяемого метода.

  • Возвращаемый тип может отличаться от возвращаемого типа переопределяемого метода, но он должен быть производным классом от возвращаемого значения родительского класса (в Java 5 и более ранних версиях возвращаемый тип должен совпадать, а в Java 7 и более поздних версиях может отличаться).

  • Уровень доступа не может быть ниже уровня доступа переопределяемого метода в родительском классе. Например: если метод в родительском классе объявлен как public, то при переопределении этого метода в подклассе его нельзя объявить как protected.

  • Методы-члены родительского класса могут переопределяться только его подклассами.

  • Методы, объявленные как final, нельзя переопределять.

  • Методы, объявленные как static, нельзя переопределять, но их можно объявить повторно.

  • Если подкласс и родительский класс находятся в одном пакете, подкласс может переопределять все методы родительского класса, кроме методов, объявленных как private и final.

  • Если подкласс и родительский класс находятся не в одном пакете, подкласс может переопределять только не-final методы родительского класса, объявленные как public и protected.

  • Переопределяющий метод может выбрасывать любое непроверяемое исключение, независимо от того, выбрасывает ли исключение переопределяемый метод. Однако переопределяющий метод не может выбрасывать новые проверяемые исключения или более широкие проверяемые исключения, чем объявленные переопределяемым методом, тогда как обратное разрешено.

  • Конструкторы нельзя переопределять.

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


Использование ключевого слова super

Когда нужно вызвать переопределённый метод родительского класса в подклассе, необходимо использовать ключевое слово super.

Код файла TestDog.java:

class Animal{ public void move(){ System.out.println("Животные могут двигаться"); } } class Dog extends Animal{ public void move(){ super.move(); //Вызов метода родительского класса с помощью super System.out.println("Собаки могут бегать и ходить"); } } public class TestDog{ public static void main(String args[]){ Animal b = new Dog(); //объект Dog b.move(); //Выполнить метод класса Dog } }

Результат компиляции и выполнения вышеприведённого примера следующий:

Animals can move
Dogs can run and walk

Перегрузка

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

Каждый перегруженный метод (или конструктор) должен иметь уникальный список типов параметров.

Наиболее часто используется перегрузка конструкторов.

Правила перегрузки:

  • Перегруженные методы должны изменять список параметров (число или типы параметров должны различаться);
  • Перегруженные методы могут изменять тип возвращаемого значения;
  • Перегруженные методы могут изменять модификатор доступа;
  • Перегруженные методы могут объявлять новые или более широкие проверяемые исключения;
  • Методы могут быть перегружены в том же классе или в подклассе.
  • Тип возвращаемого значения нельзя использовать в качестве критерия для различения перегруженных функций.

Пример

Код файла Overloading.java:

public class Overloading { public int test(){ System.out.println("test1"); return 1; } public void test(int a){ System.out.println("test2"); } //Следующие два имеют разный порядок типов параметров public String test(int a,String'] s){ System.out.println("test3']"); return "returntest3"; } public'] String test(String s,int'] a){ System.out.println("test4']"); return "returntest4"; } public'] static void main(String[] args){ Overloading o = new Overloading(); System'].out.println(o.test()); o.test'](1); System.out.println(o.test'](1,"test3")); System.out'].println(o.test("test4']",1)); } }

Различия между переопределением и перегрузкой']

Точка различия Перегруженный метод Переопределённый метод
Список параметров Должен изменять Не должен изменять
Тип возвращаемого значения Может изменять Не должен изменять
Исключение Может изменять Может сокращать или удалять, не должен выбрасывать новые или более широкие исключения
Access Может изменять Не должен устанавливать более строгие ограничения (может ослаблять ограничения)

Итог

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

  • (1) Перегрузка методов — это когда класс определяет несколько методов с одинаковым именем, но их параметры различаются по количеству или имеют одинаковое количество, но разные типы и порядок; это называется перегрузкой методов.
  • (2) Переопределение метода — это когда в подклассе существует метод с тем же именем, что и метод в родительском классе, и количество и типы параметров совпадают, и возвращаемое значение также совпадает; это называется переопределением.
  • (3) Перегрузка методов — это проявление полиморфизма внутри класса, тогда как переопределение методов — это проявление полиморфизма между подклассом и родительским классом.

Другие расширения