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:
Parabéns pela postagem ficou muito bem claro pra mim o conceito e antes, parecia algo muito distância.
Sucesso!
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