Quando uma subclasse fornece uma implementação específica para um método que já está definido em sua classe pai, ela é chamada de substituição de método. O método substituído na subclasse deve ter os mesmos parâmetros de nome e tipo de retorno que o método na classe pai.
Regras para substituição de método
- Os parâmetros de nome e o tipo de retorno devem corresponder ao método pai.
- Java escolhe qual método executar em tempo de execução com base no tipo de objeto real e não apenas no tipo de variável de referência.
- Os métodos estáticos não podem ser substituídos.
- O @Override anotação detecta erros como erros de digitação em nomes de métodos.
class Animal { void move(){ System.out.println( 'Animal is moving.'); } void eat(){ System.out.println( 'Animal is eating.'); } } class Dog extends Animal{ @Override void move(){ // move method from Base class is overriden in this // method System.out.println('Dog is running.'); } void bark(){ System.out.println('Dog is barking.'); } } public class Geeks { public static void main(String[] args) { Dog d = new Dog(); d.move(); d.eat(); d.bark(); } }
Saída
Dog is running. Animal is eating. Dog is barking.
Explicação: A classe Animal define funcionalidades básicas como mover() e comer() . A classe Dog herda de Animal e substituições o método move() para fornecer um comportamento específico O cachorro está correndo. Ambas as classes podem acessar seus próprios métodos. Ao criar um objeto Dog, chamar move() executa o método substituído.

Casos especiais em substituição
1. Chamando o método pai usando super
O super palavra-chave pode invocar o método da classe pai a partir do método de substituição.
Javaclass Parent{ void show(){ System.out.println('Parent's show()'); } } class Child extends Parent{ @Override void show(){ super.show(); System.out.println('Child's show()'); } } public class Main{ public static void main(String[] args){ Parent obj = new Child(); obj.show(); } }
Saída
Parent's show() Child's show()
2. Os métodos finais não podem ser substituídos
Se não quisermos que um método seja substituído, declaramo-lo como final . Por favor veja Usando Final com Herança .
autômatos finitos determinísticosJava
class Parent{ // Can't be overridden final void show(){ } } class Child extends Parent{ // This would produce error void show() {} }
Saída :
3. Métodos estáticos
- Os métodos estáticos não podem ser substituídos; definir um método estático em uma subclasse com a mesma assinatura da superclasse oculta o método da superclasse.
- Os métodos de instância podem ser substituídos, mas uma subclasse não pode substituir um método estático da superclasse.
- Um método estático em uma subclasse com a mesma assinatura de um método estático da superclasse oculta o método original.
class Parent{ static void staticMethod(){ System.out.println('Parent static method'); } void instanceMethod(){ System.out.println('Parent instance method'); } } class Child extends Parent{ static void staticMethod(){ // Hides Parent's static method System.out.println('Child static method'); } @Override void instanceMethod(){ // Overrides Parent's instance method System.out.println('Child instance method'); } } public class GFG{ public static void main(String[] args){ Parent p = new Child(); // Calls Parent's static method (hiding) p.staticMethod(); // Calls Child's overridden instance method p.instanceMethod(); } }
Saída
Parent static method Child instance method
4. Métodos Privados
- Os métodos privados não podem ser substituídos porque não são visíveis para as subclasses.
- Um método de subclasse com o mesmo nome é tratado como um novo método independente não relacionado à classe pai.
class Parent{ private void display(){ System.out.println('Parent private method'); } } class Child extends Parent{ void display(){ // This is a new method not overriding System.out.println('Child method'); } } public class GFG{ public static void main(String[] args){ Child c = new Child(); // Calls Child's method c.display(); } }
Saída
Child method
5. Tipos de retorno covariante
- Na substituição de método, o tipo de retorno do método substituído pode ser uma subclasse do tipo de retorno do método substituído.
- Este recurso é conhecido como tipo de retorno covariante e permite tipos de retorno mais específicos na subclasse.
class Parent{ Parent getObject(){ System.out.println('Parent object'); return new Parent(); } } class Child extends Parent{ @Override // Covariant return type Child getObject() { System.out.println('Child object'); return new Child(); } } public class GFG{ public static void main(String[] args){ Parent obj = new Child(); // Calls Child's method obj.getObject(); } }
Saída
Child object
Tratamento de exceções na substituição
- O método de substituição não pode lançar exceções verificadas novas ou mais amplas do que o método na superclasse.
- Ele pode gerar menos exceções verificadas ou mais restritas.
- Ele pode lançar qualquer exceção não verificada (como RuntimeException), independentemente do método da superclasse.
import java.io.IOException; class Parent { void display() throws IOException { System.out.println('Parent method'); } } class Child extends Parent { @Override void display() throws IOException { System.out.println('Child method'); } } public class GFG{ public static void main(String[] args){ // Parent reference Child object Parent obj = new Child(); try{ // Calls Child's overridden method obj.display(); } catch (IOException e){ System.out.println('Exception caught: ' + e.getMessage()); } } }
Saída
Child method
Por que usamos substituição de método?
- Para alterar ou aprimorar o comportamento de um método existente em uma subclasse.
- Para obter polimorfismo em tempo de execução — as chamadas de método dependem do tipo de objeto real.
- Reutilizar nomes de métodos reduzindo logicamente a redundância.
Exemplo da vida real: sistema de gestão de funcionários
Vamos entender a substituição com uma analogia do mundo real.
Imagine o Sistema de Gestão de Funcionários de uma organização. Todos os funcionários compartilham alguns comportamentos como raiseSalary() e promote() mas a lógica difere para diferentes funções, como Gerente ou Engenheiro. Podemos criar um único array Employee onde funcionários individuais são de diferentes tipos (técnico de vendas, etc.) e chamar suas funções. Isso simplifica muito o código geral.
Javaabstract class Employee { abstract void raiseSalary(); abstract void promote(); } class Manager extends Employee{ @Override void raiseSalary(){ System.out.println( 'Manager salary raised with incentives.'); } @Override void promote(){ System.out.println( 'Manager promoted to Senior Manager.'); } } class Engineer extends Employee{ @Override void raiseSalary(){ System.out.println( 'Engineer salary raised with bonus.'); } @Override void promote(){ System.out.println( 'Engineer promoted to Senior Engineer.'); } } public class Company{ public static void main(String[] args){ Employee[] employees = { new Manager() new Engineer() }; System.out.println('--- Raising Salaries ---'); for (Employee e : employees){ e.raiseSalary(); } System.out.println('n--- Promotions ---'); for (Employee e : employees) { e.promote(); } } }
Saída
--- Raising Salaries --- Manager salary raised with incentives. Engineer salary raised with bonus. --- Promotions --- Manager promoted to Senior Manager. Engineer promoted to Senior Engineer.
Explicação: Embora os objetos Manager e Engineer sejam referidos usando o tipo Employee, Java chama os métodos substituídos dos objetos reais em tempo de execução, demonstrando o envio de método dinâmico (polimorfismo de tempo de execução).
Kat Timpf é advogada
Artigo relacionado: Sobrecarga e substituição de método