Oi! Você já usa métodos Java e sabe muito sobre eles. Como funciona a sobreposição de métodos - 1Certamente você já se deparou com uma classe com muitos métodos que possuem o mesmo nome, mas listas de argumentos diferentes. Você deve se lembrar que nesses casos usamos sobrecarga de método. Hoje vamos dar uma olhada em uma situação diferente. Imagine que temos um método comum, mas ele deve fazer coisas diferentes dependendo da classe em que é chamado. Como implementamos esse comportamento? Para entender isso, vamos pegar a Animalclasse pai, que representa os animais, e criar um speakmétodo nela:

public class Animal {
  
   public void speak() {

       System.out.println("Hello!");
   }
}
Embora tenhamos acabado de começar a escrever nosso programa, você provavelmente pode ver um problema em potencial: o mundo está cheio de muitos animais e todos eles "falam" de maneira diferente: gatos miam, patos grasnam, cobras sibilam, etc. Nosso objetivo é simples: Como funciona a sobreposição de métodos - 2nós quer evitar criar um monte de métodos para falar. Ao invés de criar um meow()método para miar, hiss()sibilar, etc., queremos que a cobra sibile, o gato mie e o cachorro latir quando o speak()método for chamado. Podemos conseguir isso facilmente usando substituição de método . A Wikipédia explica o termo da seguinte forma: Substituição de método, na programação orientada a objetos, é um recurso de linguagem que permite que uma subclasse ou classe filha forneça uma implementação específica de um método que já é fornecido por uma de suas superclasses ou classes pai. Isso é basicamente correto. A substituição permite que você pegue algum método de uma classe pai e escreva sua própria implementação em cada classe derivada. A nova implementação na classe filha "substitui" a da classe pai. Vamos ver como isso se parece com um exemplo. Vamos criar 4 descendentes da nossa Animalclasse:

public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
Aqui está um pequeno macete para o futuro: para sobrescrever os métodos de uma classe pai, entre no código da classe derivada no IntelliJ IDE , pressione Ctrl+O e selecione Substituir métodos... no menu. Acostume-se a usar teclas de atalho desde o início. Eles vão acelerar a codificação! Para obter o comportamento desejado, fizemos algumas coisas:
  1. Em cada classe descendente, criamos um método com o mesmo nome do método na classe pai.
  2. Dissemos ao compilador que não estamos apenas dando ao método o mesmo nome da classe pai, mas queremos sobrescrever seu comportamento. Essa "mensagem" para o compilador é transmitida por meio da anotação @Override .
    A anotação @Override acima de um método informa ao compilador (bem como a outros programadores que leem seu código): "Não se preocupe. Isso não é um erro ou descuido. Estou ciente de que esse método já existe e quero substituí-lo .

  3. Escrevemos a implementação necessária para cada classe descendente. Quando o speak()método é chamado, uma cobra deve assobiar, um urso deve rosnar e assim por diante.
Vamos ver como isso funciona em um programa:

public class Main {

   public static void main(String[] args) {

       Animal animal1 = new Dog();
       Animal animal2 = new Cat();
       Animal animal3 = new Bear();
       Animal animal4 = new Snake();
      
       animal1.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
Saída do console:

Woof! 
Meow! 
Growl! 
Hiss!
Ótimo, tudo funciona como deveria! Criamos 4 variáveis ​​de referência cujo tipo é a Animalclasse pai e atribuímos a elas 4 objetos diferentes das classes descendentes. Como resultado, cada objeto se comporta de maneira diferente. Para cada uma das classes derivadas, o speak()método substituído substitui o método existente speak()da Animalclasse (que simplesmente exibe "Speaking:" no console). Como funciona a sobreposição de métodos - 3A substituição do método tem várias limitações:
  1. Um método substituído deve ter os mesmos argumentos que o método na classe pai.

    Se o speakmétodo da classe pai receber a Stringcomo entrada, o método substituído na classe descendente também deverá receber a Stringcomo entrada. Caso contrário, o compilador irá gerar um erro:

    
    public class Animal {
    
       public void speak(String s) {
    
           System.out.println("Speaking: " + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override // Error!
       public void speak() {
           System.out.println("Meow!");
       }
    }
    

  2. O método substituído deve ter o mesmo tipo de retorno que o método na classe pai.

    Caso contrário, obteremos um erro de compilação:

    
    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String speak() {         // Error!
           System.out.println("Meow!");
           return "Meow!";
       }
    }
    

  3. O modificador de acesso do método substituído também não pode diferir do original:

    
    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void speak() {      // Error!
           System.out.println("Meow!");
       }
    }
    
Em Java, a substituição de método é uma maneira de implementar o polimorfismo. Isso significa que sua principal vantagem é aquela flexibilidade de que falamos anteriormente. Podemos construir uma hierarquia simples e lógica de classes, cada uma com um comportamento específico (latidos de cães, miados de gatos), mas uma única interface — um único speak()método para todos, em vez de vários métodos diferentes, por exemplo bark(), meow(), etc.