Throws x extends

2 respostas
O

Amigos,
Tenho uma classe conforme abaixo:

public class Th {
    int A() throws Exception  {
        return 1;
    }
    
}
e uma outra q estenda ela
public class Th1 extends Th {
    int A() throws IOException  { // ou qualquer exceção filha
        return 2;
    }
}

sei que para SUBSCRITA de metodos devemos usar excecoes MAIS restritiva, porem prq ???

Obrigado

2 Respostas

M

Em relação a sobrescrita de métodos e exceções devemos lembrar que as exceções fazem parte da assinatura do método.
Logo um método sobrescrito deve ter o mesmo tipo de retorno, mesma lista de parâmetros e exceções do método que ele sobrescreveu, com uma implementação diferente.
Se mudar a lista de parâmetros então será uma sobrecarga e aí será permitido mudar o tipo de retorno e fugir às regras de exceções para os sobrescritos.

1-) o método que sobrescreve pode lançar qualquer exceção não-verificada (unchecked exception), ou seja, qualquer sub-classe de RuntimeException
2-) o método que sobrescreve não deve lançar exceções verificadas novas ou mais abrangentes que as declaradas pelo método que está sendo sobrescrito
3-) o método que sobrescreve poderá lançar exceções mais restritivas ou menos abrangentes

É assim por causa do polimorfismo. Juntemos a herança com a sobrescrita. O que teremos? Teremos a implementação de comportamento especializados nas classes filhas. Porém, alguém tem que garantir que as classes filhas implementem os métodos de acordo com algumas regras (tipo de retorno, mesma lista de parâmetros e exceções).

Então a superclasse entra em ação e diz para a subclasse: “ok, você quer sobrescrever um método meu? Então o seu método deve retornar um boolean, deve receber uma String e lançar um IOException. Caso tente lançar uma exceção mais abrangente que IOException (uma classe hierarquicamente superior, ou de outra hierarquia), eu não o reconhecerei como um método que sobrescreve meu método.” E nesse caso também não será uma sobrecarga (não mudou parâmetro).

Assim nos beneficiaremos do polimorfismo. Utilizando o seu código de exemplo, imagine que em algum ponto da sua aplicação é aguardo um objeto do tipo Th para a execução do método A. Mas por algum motivo tinha que ser executado um comportamento diferente. Então você enviará um objeto do tipo Th1 (perfeito! É permitido), e o método executado continua sendo o método A. Porém ele vai executar o desejado comportamento diferente.

E você criou outras classes filhas de Th (Th2, Th3…) e cada uma tem a sua implementação de A.

Agora, em outros pontos da sua aplicação, você tem que executar o método A, às vezes da classe Th1, outras vezes da classe Th2 e assim vai. Então nesses pontos basta você aguardar um objeto do tipo Th e executar o método A. Porém se você que executar o método A de um objeto Th2, então basta enviar uma referência ao objeto Th2 que seu respectivo método A será executado.

Retornando às exceções. Como é que um método A de uma classe filha poderá ser executado se ele quer lançar uma exceção que não está no contrato com a superclasse? Como é que ele quer lançar um SQLException se o método da superclasse (aquele que foi sobrescrito) nem sabe quem é SQLException e só permitiu alguém que se enquadre em IOException?

Parece complicado, mas não é. Requer alguns leituras e alguns exemplos. :shock:

Qualquer coisa peça ajuda.

Boa sorte.

ViniGodoy

Lembre que você pode fazer algo assim:

Th th = new Th1(); try { th.A(); } catch (Exception e) {}

Note que a classe Th1 apenas lança uma IOException. E o catch, de Exception, será capaz de capturar uma IOException, já que ela é filha de exception.

Agora, vamos imaginar que você possível fazer o inverso. Que Th1 pudesse lançar uma exceção menos restritiva. Ou seja, imagine que quem lança Exception é Th1 e que quem lança IOException é Th. O código cima, para quem usa essas classes, ficaria assim:

Th th = new Th1(); try { th.A(); } catch (IOException e) {}

Agora pude fazer o catch só de IOException, já que é a exception que Th lança. Mas, th1 agora dispara uma outra exception verificada qualquer, como uma SocketException (na assinatura de Th, ela pode disparar agora qualquer exception). O que acontece? Aquele catch está furado, ele não captura SocketException.

Por isso existe a restrição. O pai deve ter certeza que sua lista de exceptions é capaz de capturar todas as exceções verificadas de seus filhos. Caso contrário, caso um filho fosse atribuído a ele, teríamos um tratamento de exceções inválido.

Criado 5 de abril de 2010
Ultima resposta 6 de abr. de 2010
Respostas 2
Participantes 3