Java - переопределение
В предыдущей главе мы говорили о суперклассах и подклассах. Если класс наследует метод от своего суперкласса, есть шанс переопределить метод при условии, что он не помечен как окончательный.
Преимущество переопределения: возможность определять поведение, специфичное для типа подкласса, что означает, что подкласс может реализовать метод родительского класса в зависимости от его требований.
В объектно-ориентированных терминах переопределение означает переопределение функциональности существующего метода.
пример
Давайте посмотрим на пример.
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
}
}
Это даст следующий результат -
Вывод
Animals can move
Dogs can walk and run
В приведенном выше примере вы можете видеть, что, хотя bэто тип Animal, он запускает метод move в классе Dog. Причина этого: во время компиляции выполняется проверка ссылочного типа. Однако во время выполнения JVM определяет тип объекта и запускает метод, принадлежащий этому конкретному объекту.
Следовательно, в приведенном выше примере программа будет правильно скомпилирована, поскольку в классе Animal есть метод move. Затем во время выполнения он запускает метод, специфичный для этого объекта.
Рассмотрим следующий пример -
пример
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
System.out.println("Dogs can walk and run");
}
public void bark() {
System.out.println("Dogs can bark");
}
}
public class TestDog {
public static void main(String args[]) {
Animal a = new Animal(); // Animal reference and object
Animal b = new Dog(); // Animal reference but Dog object
a.move(); // runs the method in Animal class
b.move(); // runs the method in Dog class
b.bark();
}
}
Это даст следующий результат -
Вывод
TestDog.java:26: error: cannot find symbol
b.bark();
^
symbol: method bark()
location: variable b of type Animal
1 error
Эта программа выдаст ошибку времени компиляции, поскольку у ссылочного типа b Animal нет метода с именем bark.
Правила замены метода
Список аргументов должен быть точно таким же, как у переопределенного метода.
Тип возвращаемого значения должен быть таким же или подтипом типа возвращаемого значения, объявленного в исходном переопределенном методе в суперклассе.
Уровень доступа не может быть более строгим, чем уровень доступа замещаемого метода. Например: если метод суперкласса объявлен общедоступным, то метод переопределения в подклассе не может быть частным или защищенным.
Методы экземпляра можно переопределить, только если они унаследованы подклассом.
Метод, объявленный как final, не может быть переопределен.
Метод, объявленный статическим, не может быть переопределен, но может быть объявлен повторно.
Если метод не может быть унаследован, его нельзя переопределить.
Подкласс в том же пакете, что и суперкласс экземпляра, может переопределить любой метод суперкласса, который не объявлен частным или окончательным.
Подкласс в другом пакете может только переопределить неокончательные методы, объявленные общедоступными или защищенными.
Переопределяющий метод может вызывать любые исключения снятия отметки, независимо от того, генерирует ли переопределенный метод исключения или нет. Однако метод переопределения не должен генерировать проверенные исключения, которые являются новыми или более широкими, чем те, которые объявлены переопределенным методом. Переопределяющий метод может вызывать меньшее или меньшее количество исключений, чем переопределенный метод.
Конструкторы нельзя переопределить.
Использование супер-ключевого слова
При вызове версии суперкласса переопределенного метода super ключевое слово используется.
пример
class Animal {
public void move() {
System.out.println("Animals can move");
}
}
class Dog extends Animal {
public void move() {
super.move(); // invokes the super class method
System.out.println("Dogs can walk and run");
}
}
public class TestDog {
public static void main(String args[]) {
Animal b = new Dog(); // Animal reference but Dog object
b.move(); // runs the method in Dog class
}
}
Это даст следующий результат -
Вывод
Animals can move
Dogs can walk and run