CodeGym /Cursos /JAVA 25 SELF /Sobrescrita de métodos (override), anotação @Override

Sobrescrita de métodos (override), anotação @Override

JAVA 25 SELF
Nível 17 , Lição 1
Disponível

1. Sobrescrita de método

Na vida, é comum que o “descendente” se comporte de modo especial. Por exemplo, todos os animais sabem emitir sons, mas o gato — “miau”, o cachorro — “au au”, e o programador — “ih, bug de novo!”. Em programação, isso é implementado por meio da sobrescrita de método (override).

Sobrescrita de método é quando uma subclasse fornece sua própria implementação de um método que já foi declarado na classe-pai. Ou seja, “substitui” o comportamento padrão por algo mais específico.

Analogia. Se imaginarmos a classe-pai como uma receita assinada de borscht, então a sobrescrita é quando a avó adiciona o ingrediente secreto dela. Continua sendo borscht, mas o sabor de cada um é particular.

Para sobrescrever um método, é preciso declarar na classe filha um método com exatamente a mesma assinatura (nome, parâmetros, tipo de retorno) que o do pai.

Exemplo: animais e seus sons

class Animal {
    void makeSound() {
        System.out.println("Some generic animal sound");
    }
}

class Dog extends Animal {
    // Sobrescrevemos o método makeSound()
    void makeSound() {
        System.out.println("Woof!");
    }
}

class Cat extends Animal {
    // Sobrescrevemos o método makeSound()
    void makeSound() {
        System.out.println("Meow!");
    }
}

Agora, se você criar um objeto Dog e chamar makeSound(), você ouvirá "Woof!", e não "Some generic animal sound".

Demonstração em código

public class Main {
    public static void main(String[] args) {
        Animal generic = new Animal();
        Dog dog = new Dog();
        Cat cat = new Cat();

        generic.makeSound(); // Some generic animal sound
        dog.makeSound();     // Woof!
        cat.makeSound();     // Meow!
    }
}

Importante: se a subclasse não tiver um método com a mesma assinatura, será utilizado o método do pai.

2. Anotação @Override: para que serve e como usar

Em Java, é comum marcar métodos sobrescritos com a anotação @Override. Não é apenas um enfeite no código, mas uma ferramenta útil:

  • O compilador verifica se você realmente está sobrescrevendo um método do pai. Se houver erro no nome, no tipo de parâmetro ou no tipo de retorno — o compilador emitirá um erro.
  • Melhora a legibilidade do código. Outro programador vê imediatamente: “Ah, este método sobrescreve o do pai”.

Exemplo com @Override

class Dog extends Animal {
    @Override
    void makeSound() {
        System.out.println("Woof!");
    }
}

Se você escrever acidentalmente void makeSond() (erro de digitação!) em um método anotado com @Override, o compilador reclamará: "Method does not override or implement a method from a supertype".

Padrões modernos. Usar @Override é uma boa prática e um padrão da indústria. Mesmo que o compilador não exija, sempre coloque essa anotação — isso facilita a vida para você e para os colegas.

3. Como funciona a chamada de um método sobrescrito

Quando você chama um método em um objeto da subclasse, será usada a implementação da subclasse, mesmo que a variável seja declarada como o tipo do pai.

Exemplo: polimorfismo em ação

Animal animal = new Dog();
animal.makeSound(); // "Woof!", e não "Some generic animal sound"

Aqui a variável é do tipo Animal, mas na verdade ela guarda um objeto Dog. O Java “entende” que deve chamar o método sobrescrito de Dog. Isso é polimorfismo (mais detalhes nas próximas aulas).

4. Restrições e regras de sobrescrita

Assinatura do método

  • O nome, o tipo e a ordem dos parâmetros devem coincidir com os do método no pai.
  • O tipo de retorno deve coincidir ou ser covariante (subtipo do tipo de retorno do pai). Por exemplo, se o pai retorna Animal e o filho retorna Dog, isso é permitido.

Modificadores de acesso

  • Não é permitido tornar o acesso mais restrito do que no pai.
  • Se o método do pai é public, então o sobrescrito também deve ser public.
  • Se o método do pai é protected, o sobrescrito pode ser protected ou public.

Se você tentar fazer o contrário, o compilador dirá: "Cannot reduce the visibility of the inherited method".

Exceções

  • O método sobrescrito não pode lançar uma nova checked exception que não esteja na declaração do pai.
  • É permitido lançar menos exceções do que o pai, ou seus subtipos.

static, final, private

  • Não é possível sobrescrever métodos declarados como static ou final, nem métodos privados (private).
  • static — é ocultação (hiding), não sobrescrita.
  • final — não pode ser sobrescrito de forma alguma; o Java protege tais métodos.
  • private — não é visível no filho, não pode ser sobrescrito (só é possível declarar um novo método com o mesmo nome).

Construtores

Construtores não são herdados nem sobrescritos. Cada classe tem seus próprios construtores.

5. Evoluindo o aplicativo didático “Zoológico”

Hora de aplicar a teoria na prática! Vamos continuar evoluindo nosso aplicativo de “zoológico”.

Etapa 1. Classe base Animal

public class Animal {
    public void makeSound() {
        System.out.println("Some generic animal sound");
    }

    public void sleep() {
        System.out.println("Zzz...");
    }
}

Etapa 2. Subclasses Dog e Cat

public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Woof!");
    }

    // Método adicional apenas para Dog
    public void fetch() {
        System.out.println("Dog brings the stick!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow!");
    }

    // Método adicional apenas para Cat
    public void scratch() {
        System.out.println("Cat scratches the sofa!");
    }
}

Etapa 3. Usando a sobrescrita

public class ZooTest {
    public static void main(String[] args) {
        Animal generic = new Animal();
        Animal dog = new Dog();
        Animal cat = new Cat();

        generic.makeSound(); // Some generic animal sound
        dog.makeSound();     // Woof!
        cat.makeSound();     // Meow!

        // dog.fetch(); // Erro! A variável do tipo Animal não conhece fetch()
        // cat.scratch(); // Análogo

        // Mas se especificarmos o tipo explicitamente:
        if (dog instanceof Dog) {
            ((Dog) dog).fetch(); // Dog brings the stick!
        }
        if (cat instanceof Cat) {
            ((Cat) cat).scratch(); // Cat scratches the sofa!
        }
    }
}

Comentário:
O método makeSound() funciona de forma polimórfica — é chamada a versão do método do tipo real do objeto. Já métodos específicos (fetch, scratch) ficam disponíveis apenas via casting explícito — isso é importante para entender como herança e sobrescrita funcionam.

6. Exemplo com tipo de retorno (covariância)

Às vezes queremos que o método sobrescrito retorne um tipo mais “estreito”. Por exemplo:

class Animal {
    Animal getFriend() {
        return new Animal();
    }
}

class Dog extends Animal {
    @Override
    Dog getFriend() { // Tipo de retorno — Dog, subtipo de Animal
        return new Dog();
    }
}

Isso se chama covariância do tipo de retorno e é permitido no Java (desde o Java 5).

7. O que acontece se você não usar @Override?

Se você errar no nome do método ou nos parâmetros, o Java não reclamará se não houver a anotação @Override. Como resultado, você não sobrescreverá, mas criará um novo método, e o comportamento esperado não mudará.

Exemplo de erro

class Dog extends Animal {
    // Erro de digitação: makeSoud em vez de makeSound
    void makeSoud() {
        System.out.println("Woof!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        dog.makeSound(); // Imprimirá "Some generic animal sound"
    }
}

Se houvesse @Override, o compilador emitiria um erro: "Method does not override or implement a method from a supertype".

8. Erros típicos ao sobrescrever métodos

Erro nº 1: ausência da anotação @Override.
Sem ela é fácil errar no nome do método ou nos parâmetros. Como resultado, o método não será sobrescrito e o programa não se comportará como você esperava.

Erro nº 2: tentar restringir o modificador de acesso.
Se o método do pai é public e você escreve protected ou private — ocorrerá erro de compilação.

Erro nº 3: assinatura não correspondente.
Se os parâmetros diferirem ao menos no tipo — isso já não é sobrescrita, mas sobrecarga (overloading).

Erro nº 4: tentar sobrescrever um método final ou static.
O Java não permite: final protege contra sobrescrita, e métodos static não são sobrescritos (apenas ocultados).

Erro nº 5: mudar o tipo de retorno para um incompatível.
Só é permitido retornar um subtipo do tipo de retorno do pai (covariância), e não um tipo completamente diferente.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION