Учебники

Java — переопределение

В предыдущей главе мы говорили о суперклассах и подклассах. Если класс наследует метод от своего суперкласса, то есть шанс переопределить метод при условии, что он не помечен как финальный.

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

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

пример

Давайте посмотрим на пример.

Live Demo

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. Затем во время выполнения он запускает метод, специфичный для этого объекта.

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

пример

Live Demo

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, не может быть переопределен.

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

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

  • Подкласс в том же пакете, что и суперкласс экземпляра, может переопределить любой метод суперкласса, который не объявлен как private или final.

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

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

  • Конструкторы не могут быть переопределены.

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

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

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

Методы экземпляра могут быть переопределены, только если они наследуются подклассом.

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

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

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

Подкласс в том же пакете, что и суперкласс экземпляра, может переопределить любой метод суперкласса, который не объявлен как private или final.

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

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

Конструкторы не могут быть переопределены.

Используя супер ключевое слово

При вызове версии переопределенного метода суперкласса используется ключевое слово super .

пример

Live Demo

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
   }
}

Это даст следующий результат —