Java - Substituindo

No capítulo anterior, falamos sobre superclasses e subclasses. Se uma classe herda um método de sua superclasse, há uma chance de sobrescrever o método, desde que ele não seja marcado como final.

O benefício da substituição é: capacidade de definir um comportamento específico para o tipo de subclasse, o que significa que uma subclasse pode implementar um método de classe pai com base em seus requisitos.

Em termos orientados a objetos, substituir significa substituir a funcionalidade de um método existente.

Exemplo

Vamos ver um exemplo.

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

Isso produzirá o seguinte resultado -

Resultado

Animals can move
Dogs can walk and run

No exemplo acima, você pode ver que embora bé um tipo de Animal que executa o método de movimento na classe Dog. O motivo é: Em tempo de compilação, a verificação é feita no tipo de referência. No entanto, no tempo de execução, a JVM descobre o tipo de objeto e executa o método que pertence a esse objeto específico.

Portanto, no exemplo acima, o programa irá compilar corretamente, uma vez que a classe Animal possui o método move. Então, em tempo de execução, ele executa o método específico para aquele objeto.

Considere o seguinte exemplo -

Exemplo

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();
   }
}

Isso produzirá o seguinte resultado -

Resultado

TestDog.java:26: error: cannot find symbol
      b.bark();
       ^
  symbol:   method bark()
  location: variable b of type Animal
1 error

Este programa gerará um erro em tempo de compilação, pois o tipo de referência de b Animal não tem um método com o nome de bark.

Regras para Substituição de Método

  • A lista de argumentos deve ser exatamente a mesma do método sobrescrito.

  • O tipo de retorno deve ser o mesmo ou um subtipo do tipo de retorno declarado no método original sobrescrito na superclasse.

  • O nível de acesso não pode ser mais restritivo do que o nível de acesso do método substituído. Por exemplo: Se o método da superclasse for declarado público, o método de substituição na subclasse não pode ser privado ou protegido.

  • Os métodos de instância podem ser substituídos apenas se forem herdados pela subclasse.

  • Um método declarado final não pode ser substituído.

  • Um método declarado como estático não pode ser substituído, mas pode ser declarado novamente.

  • Se um método não pode ser herdado, ele não pode ser substituído.

  • Uma subclasse dentro do mesmo pacote que a superclasse da instância pode substituir qualquer método da superclasse que não seja declarado privado ou final.

  • Uma subclasse em um pacote diferente só pode substituir os métodos não finais declarados públicos ou protegidos.

  • Um método de substituição pode lançar quaisquer exceções desmarcadas, independentemente de o método substituído lançar exceções ou não. No entanto, o método de substituição não deve lançar exceções verificadas que são novas ou mais amplas do que as declaradas pelo método de substituição. O método de substituição pode lançar exceções mais restritas ou menos do que o método substituído.

  • Construtores não podem ser substituídos.

Usando a super palavra-chave

Ao invocar uma versão da superclasse de um método sobrescrito, o super palavra-chave é usada.

Exemplo

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

Isso produzirá o seguinte resultado -

Resultado

Animals can move
Dogs can walk and run