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