Sobrescrita de método com exceção

Estou com uma dúvida neste código, quando tento executar a linha “a.foo();”, estou dizendo pra pegar a referência da classe A e executar o método da class SubB2, certo?
Pois bem, pq o compilador reclama que devo tratar a exceção Exception no método sobrescrito? Uma vez que estou sobrescrevendo o método sem tal possibilidade de lançar esta exceção?

package teste;

class A {
   void foo() throws Exception {
       throw new Exception();
   }
}

class SubB2 extends A {
	@Override
   void foo () {
       System.out.println("B");
   }
}

public class Babble {

	public static void main(String[] args) {
       A a = new SubB2();
       a.foo(); 
	}
}

Olá, veja, você declarou um throws Exception e isso te força a passar a exceção para frente. isso esta na assinatura do método, então tem que ser implementado.

Boa tarde gRoOve.

Voce esqueceu de um pequeno detalhe, ou seja, na hora de tipar a variável “a”, voce a tipou como sendo do tipo de classe “A”, mesmo que voce a instancie com as suas sub-classes, voce não faz casting direto desta forma, a referência sempre será da Classe A, porque ela é do tipo classe A, que invocará o método foo() da classe que lança a exceção. A menos, é claro que voce declare uma instância como sendo do tipo SubB2 e a instancie com a classe A fazendo o casting para (SubB2), senão vejamos.

public class Babble {  
  
    public static void main(String[] args) {
 
       // Aqui o método foo() invocado é do Classe A 
       A a = new SubB2();  
       a.foo();

       // Agora voce consegue invocar o método foo() da classe SubB2;
      SubB2 b2 = (SubB2)new A();
      b2.foo();

      // Ou direto desta forma
      SubB2 b2 = new SubB2();
      b2.foo();
    }  
}

Lembre-se, voce pode até instanciar a classe a pai com os seus filhos, porém ele nunca deixará de ser pai, e só terá as características do pai.

Lembre-se também que em Orientação a Objetos, as regras de herança também funcionam em que um filho jamais conseguirá ser o genitor do seu pai.

Um abraço.

[quote=discorpio]a referência sempre será da Classe A, porque ela é do tipo classe A, que invocará o método foo() da classe que lança a exceção. A menos, é claro que voce declare uma instância como sendo do tipo SubB2 e a instancie com a classe A fazendo o casting para (SubB2), senão vejamos.
[/quote]
Pelo que li no livro da Kathy, apesar de a referência ser da Classe A, a JVM seleciona dinamicamente o método do objeto instanciado, independente da referência.

Deixa eu tentar entender então, independente de eu ter declarado o throws Exception no método da classe Pai e ter sobrescrito este método na classe filha, a cláusula throws vai junto para o método sobrescrito apesar de eu não declarar isto? Fiquei confuso agora…

Boa tarde a todos.

[quote=gRoOve][quote=discorpio]a referência sempre será da Classe A, porque ela é do tipo classe A, que invocará o método foo() da classe que lança a exceção. A menos, é claro que voce declare uma instância como sendo do tipo SubB2 e a instancie com a classe A fazendo o casting para (SubB2), senão vejamos.
[/quote]
Pelo que li no livro da Kathy, apesar de a referência ser da Classe A, a JVM seleciona dinamicamente o método do objeto instanciado, independente da referência.

Deixa eu tentar entender então, independente de eu ter declarado o throws Exception no método da classe Pai e ter sobrescrito este método na classe filha, a cláusula throws vai junto para o método sobrescrito apesar de eu não declarar isto? Fiquei confuso agora…[/quote]

Negativo, o método sobrescrito, substitui todo o código do método da classe pai, passando ser ele o método atual da classe filha, caso voce queira acrescentar o conteúdo de processamento da classe pai para dentro do método sobrescrito na classe filha, voce tem que utilizar a cláusula “super.foo()”, desta forma:

class A {  
   void foo() throws Exception {  
       throw new Exception();  
   }  
}  
  
class SubB2 extends A {  
    @Override  
   void foo () {
        /* Com super voce esta incluindo a implementação do metodo foo() da classe A,
            incluindo o lançamento da Exceção. */
       super.foo();

       System.out.println("B");  
   }  
}

Explicando melhor o que livro da Kathy quer dizer:

Na declaração:

   A a = new SubB2();

O JVM analise o objeto a ser instanciado e verificar que são de classes diferentes, a primeira verificação que ele faz é saber se uma classe herda da outra, depois ele verifica qual é o tipo da instância e seleciona dinamicamente os métodos do tipo da instância e não da classe que está sendo instanciada, e é por isso que existe sempre a necessidade de casting (conversão de classes). Além disso, a seleção dinâmica consegue identificar o método que foi sobrescrito através da anotação “Override”.

E lembre-se do que eu disse, pois Classes Pai não consegue enxergar métodos de classes filhas, somente o inverso é possível (filho não gera o seu pai, somente pais geram seus filhos). Por isso, não adianta voce tentar instaciar uma classe Pai que suas classes filhas.

Consegui achar a resposta no próprio livro, trata-se de mais uma particularidade, neste caso que o método pai possui uma exceção, o JVM irá selecionar o método da classe Pai mesmo que o objeto sendo utilizado seja de uma classe Filha. Quero ver é lembrar de todas essas exceções na hora da prova…

Olá, sou eu de novo.

Mais uma vez explicando melhor para que voce não se enrole na hora da prova:


   A a = new A();
   a.foo()    // Aqui ele lança a exceção.

   A a = new SubB2();
   a.foo();  /* Aqui ele continua a lançar a exceção, porque os métodos
                    carregados para a memória continuam sendo da classe A */

   /* A partir daqui em diante ele não mais vai lançar a exceção
       porque os métodos carregados para a memória são da classe SubB2
       cujo metodo foo() foi sobreescrito, apagando a exceção. */

   SubB2 b2 = (SubB2)new A();
   b2.foo();

   SubB2 b2 = new SubB2();
   b2.foo();

O método foo() da classe SubB2 só lançará a exceção da classe pai, se voce invocar dentro dele a sintaxe “super.foo();”

Cappichi

Então na verdade a JVM só selecionará o método do objeto dinamicamente quando não houver declaração de exceção, caso contrário o método chamado será da classe Pai.

Agora, isso vale para qualquer exceção declarada pelo método do Pai?

Olá gRoOve.

[quote=gRoOve]Então na verdade a JVM só selecionará o método do objeto dinamicamente quando não houver declaração de exceção, caso contrário o método chamado será da classe Pai.

Agora, isso vale para qualquer exceção declarada pelo método do Pai?[/quote]

Qualquer método da classe pai que contiver um lançamento de exceção, a exceção só sera lançada nas classes filhas se o método não tiver sido sobrescrito na filha sem a exceção.

Cappichi

Mas isso que vc acaba de falar, o código que eu postei faz exatamente ao contrário, o método foi sobrescrito na classe filha sem a exceção e mesmo assim a exceção da classe pai foi lançada.

Pelo oq eu testei rapido aqui no eclipse, o compilador verifica a exception de acordo com a variavell de referência que você utilizar, independente do objeto ao qual ela se refere.

     SubB2 b = new SubB2();
				b.foo(); // se você declara com a varivel de referencia do tipo da subClass o compilador não acusa o erro da Exception
				
				A a = new SubB2();
				a.foo(); 


Boa noite a todos.

[quote=jalonso]Pelo oq eu testei rapido aqui no eclipse, o compilador verifica a exception de acordo com a variavell de referência que você utilizar, independente do objeto ao qual ela se refere.

[code]
SubB2 b = new SubB2();
b.foo(); // se você declara com a varivel de referencia do tipo da subClass o compilador não acusa o erro da Exception

			A a = new SubB2();
			a.foo(); 

[/code][/quote]

Mas é justamente isto que eu estou tentando explicar, não adianta nada voce declarar uma variável do tipo de classe “A” que contenha um método “foo()” que lança uma exceção e joga outra exceção para cima, e tenta instanciá-la com uma sub-classe sua que contém o mesmo método “foo()” sobrescrito sem lançamento de exceção e sem jogar outra exceção para cima. Isto ocorre porque voce não faz casting direto desta forma.

Quando o método é sobrescrito, ele é totalmente substituído pelo metodo novo.

Agora, se voce não sobrescrever o metodo “foo()”, nas classes filhas, ai sim ele vai lançar a exceção, porque ele esta declarado na classe pai como exceção. Mais uma vez vamos ao exemplo.

  class A {    
     void foo() throws Exception {   // Aqui ele está lançando o tratamento da exceção para linha onde o método for invocado 
           throw new Exception();  // E aqui ele lança uma exceção.  
     }    
  }    
    
  class SubB2 extends A {    
       /* A anotação Override indica para o compilador que este método foi sobrescrito,
           ou seja, o JVM quando invoca este método, vai executar exatamente este método
           e não o da classe pai. */
       @Override 
       void foo () {   
           System.out.println("B");    
       }    
  }

  /* Repare que aqui o método foo() não foi sobrescrito,
      portanto esta herdando este método da classe pai,
      junto com todas as suas exceções. */
  class SubB3 extends A {
       void metodoQualquer() {
           System.out.println("C");
       }
   }

  public class Babble {    
    
    public static void main(String[] args) {  
  
       /* Aqui o método foo() invocado é do Classe A,
           mesmo que voce instancia com uma sub-classe,
           não adianta, porque a classe é do tipo A, portanto
           os métodos instanciados em memória, são os da
           classe A, e por isso a exceção é lançada. */ 
       A a = new SubB2();    
       a.foo();  
  
       /* Agora voce consegue invocar o método foo() da classe SubB2
           que foi sobrescrito sem a exceção, onde as duas instanciações
           abaixo, o executa sem lançamento de exceção. */
      SubB2 b2 = (SubB2)new A();  
      b2.foo();  
  
      // Ou direto desta forma  
      SubB2 b2 = new SubB2();  
      b2.foo();

      /* Aqui a exceção do método foo() vai ser disparada porque na sub-classe SubB3
          não foi sobrescrito, portanto não foi substituído, herdando-o completamente
          da classe pai. */
      SubB3 b3 = new SubB3();
      b3.foo();

        
    }    
}  

Conseguiu entender :?:

Se não, então não se preocupe que explicaremos de novo.

Um Abraço.