Métodos Sobrescritos (Overridden)


Qualquer classe que herda um método de uma superclasse tem a oportunidade de sobrescrever o método (exceto métodos marcados como final). O benefício de sobrepor é a capacidade de definir um comportamento que é específico para um tipo de subclasse particular.
Para métodos abstratos que são herdados de uma superclasse não existe escolha; deve-se implementar os métodos na subclasse, com exceção se a subclasse também seja uma classe abstrata.

public class Pessoa {  
      public void cadastrar() {
            System.out.println("Cadastro de Pessoa");
      }
}

public class PFisica extends Pessoa {   
      //método sobrescrito de Pessoa
      public void cadastrar() {
            System.out.println("Cadastro de PFisica");
      }
}

Polimorficamente é possível declarar um objeto de um tipo e referencia-lo com um de seus subtipos, por exemplo: ao declarar um objeto Pessoa, que é superclasse de PFisica, é possível instanciar esse objeto como Pessoa ou PFisica. Caso seja instanciado como Pessoa, este objeto terá acesso a todos os métodos de Pessoa. Porém, se esse objeto (do tipo Pessoa) estiver instanciado como PFisica e tentar acessar qualquer método que exista em Pessoa, o compilador irá tentar acha-lo primeiro na classe de referência (PFisica), caso não encontre, acessará o método da classe Pessoa.

public class Pessoa {  
      public void cadastrar() {
            System.out.println("Cadastro de Pessoa");
      }
}

public class PFisica extends Pessoa {
     
      //método sobrescrito de Pessoa
      public void cadastrar() {
            System.out.println("Cadastro de PFisica");
      }
     
      public void atualizar() {
            System.out.println("Atual. de PFisca");
      }

}

public class AppPessoa {
      public static void main(String[] args) {
            Pessoa pessoa = new Pessoa();
            Pessoa pessoa2 = new PFisica();
            pessoa.cadastrar();
            pessoa2.cadastrar();
            //Pessoa não possui o método atualizar()
            pessoa.atualizar();
            /* Apesar de PFisica possuir o método
             * atualizar(), a referência é da classe
 * Pessoa, que não possui o método */
            pessoa2.atualizar();
      }    
}

Um método sobrescrito não pode ter um modificador de acesso mais restrito do que o método original; por exemplo: não se pode sobrescrever um método public marcando-o como protected; porém, é possível sobrescrever um método protected como public.

public class Pessoa {       
      public void excluir() {
            System.out.println("Excluir Pessoa");
      }
}

public class PJuridica extends Pessoa {
      /* um método sobrescrito não pode ter um
       * modificador mais restrito que o método
       * original */
      protected void excluir() {
            System.out.println("Excluir PJuridica");
      }    
}

Regras para sobrescrever métodos:
·   A lista de argumentos deve combinar exatamente com a do método sobrescrito. Se não combinar, pode resultar em uma sobrecarga de método não intencional;
·   O tipo de retorno deve ser o mesmo, ou de um subtipo dele;
·   O nível de acesso não pode ser mais restrito que o nível do método original;
·   O nível de acesso pode ser menos restrito que o nível do método original;
·   Métodos de instância só podem ser sobrescritos se eles forem herdados na subclasse. Isso significa que: uma subclasse dentro de um mesmo pacote que a superclasse, pode sobrescrever qualquer método desta que não esteja marcado como private ou final; uma subclasse em um pacote diferente pode sobrescrever apenas métodos não-final marcados como public ou protected;
·   O método sobrescrito pode lançar qualquer exceção não verificada (runtime), independente de se o método sobrescrito declara a exceção;
·   O método sobrescrito não deve lançar exceções verificadas que são novas ou a mais que o método original; por exemplo, um método que declara uma FileNotFoundException não pode ser sobrescrito por um método que declara uma SQLException, Exception ou qualquer outra exceção verificada (não runtime), exceto se a exceção for uma subclasse de FileNotFoundException;
·   O método sobrescrito pode lançar menos exceções que as do método original;
·   Não se pode sobrescrever um método marcado como final;
·   Não se pode sobrescrever um método marcado como static;
·   Se um método não pode ser herdado, então ele não pode ser sobrescrito.

Invocando a versão da superclasse

Podem existir casos em que o método original deve ser executado antes do método sobrescrito. Um modo fácil de fazer isso é utilizando a palavra super seguido do nome do método da superclasse no início do corpo do método original.
A chamada do método da superclasse pode ser feita em qualquer parte do código dos métodos da subclasse.

public class Carro {   
      public void ligar() {
            System.out.println("Ligar carro");
      }
}

public class Fusca extends Carro {
      public void ligar() {
            super.ligar();
            System.out.println("Ligar fusca");
      }    
}

Para o compilador, em tempo de compilação, quando existe um objeto referenciando sua subclasse e chamando um método sobrescrito, apenas no momento da compilação, o compilador irá assumir como método de execução o método da superclasse, mesmo que o método sobrescrito na subclasse não declare exceções enquanto o método original declare. Porém, nesse caso, em tempo de execução na verdade o método chamado será o da subclasse.

public class Carro {         
      public void desligar() throws Exception {
            System.out.println("Desligar carro");
      }
}

public class Fusca extends Carro {
      public void desligar() { //sem exceção
            System.out.println("Desligar fusca");
      }    
}

public class AppCarro {
      public static void main(String[] args) {
            Carro carro = new Fusca();
            Fusca fusca = new Fusca();
            fusca.desligar();
            /* nesse caso, o método a ser executado em
             * tempo de execução seria o desligar de
             * Fusca, mas a titulo de compilação é o
             * de Carro, por isso gera erro de
             * compilação, já que o método desligar de
             * Carro declara uma exceção que não está
             * sendo tratada aqui;   */
            carro.desligar();
      }    
}

Fonte: SCJP Sun Certifi ed Programmer for Java 6 Study Guide

2 comentários:

gabrilan disse...

Parabéns pela postagem ficou muito bem claro pra mim o conceito e antes, parecia algo muito distância.
Sucesso!

Diego Góes disse...

Todos os posts que li até aqui estão muito bem explicados, dinâmica simples e de fácil compreensão. Parabéns pela iniciativa.

Postar um comentário