Après avoir lu Pourquoi les méthodes de substitution ne peuvent pas lever des exceptions, je comprends que si la méthode déclarée comme lève une exception Checked, la méthode de substitution dans une sous-classe ne peut déclarer que pour lever cette exception ou sa sous-classe:

class A {
   public void foo() throws IOException {..}
}

class B extends A {
   @Override
   public void foo() throws SocketException {..} // allowed

   @Override
   public void foo() throws SQLException {..} // NOT allowed
}

Donc, parce que SocketException IS-A IOException je peux déclarer la méthode de substitution comme lançant n'importe quelle sous-classe de IOException.

Dans mon programme, je veux invoquer la méthode de substitution déclarée comme throws FileNotFoundException IS-A IOException. également géré avec un bloc try-catch

import java.io.*;
class Sub extends Super{
    public static void main (String [] args){
        Super p = new Sub();
        try {
            p.doStuff();
        }catch(FileNotFoundException e){

        }
    }
    public void doStuff() throws FileNotFoundException{}
}

class Super{
    public void doStuff() throws IOException{}
}

Mais j'obtiens cette erreur de compilation: Screenshot

Sub.java:6: error: unreported exception IOException; must be caught or declared to be thrown
                    p.doStuff();
                             ^

Quelle est la raison de ceci? Je suis un peu confus car tout ce que la classe Base a également disponible pour les sous-classes.

La possibilité d'attraper Exception et Throwable en plus de IOException (l'opposé du concept Overriding) est également beaucoup plus déroutante.

13
Pauwelyn 24 janv. 2017 à 14:20

6 réponses

Meilleure réponse

Quelle est la raison de ceci? Je suis un peu confus car tout ce que la classe Base a également disponible pour les sous-classes.

Vous devez attraper un IOException et non un FilenotFoundException. Ceci est dû au fait que si la méthode doStuff de la sous-classe sera appelée à l'exécution, le compilateur ne le sait pas encore. Il ne connaît que la méthode doStuff de la super classe qui déclare qu'elle throws an IOException.

Pour traiter votre modification: le bloc catch peut choisir d'attraper l'exception exacte qui est attendue dans le bloc try ou il peut choisir d'attraper une superclasse de l'exception. Le raisonnement derrière cela n'a rien à voir avec le remplacement de méthode.

11
CKing 24 janv. 2017 à 18:45

Parce qu'il effectue des vérifications par type déclaré, dans ce cas Super.

Il n'est pas connu (ou vérifié) que votre p contiendra uniquement des instances de Sub. De plus, cela n'aurait pas de sens de définir une variable de superclasse et de ne l'utiliser que pour une sous-classe particulière.

Ainsi, votre Super p contient une instance d'un Super.class. Sa méthode doStuff() peut lancer tout ce qui étend IOException, disons UnsupportedEncodingException, mais vous essayez d'attraper uniquement pour FileNotFoundException, de sorte que Unsupported... peut avoir été lancé et doit être manipulé.

2
Tomas F. 24 janv. 2017 à 11:31

En déclarant p comme Super

Super p = ...

Votre compilateur sait seulement que p est une sorte de Super. Le doStuff() de Super lance un IOException, mais votre code n'attrape qu'un cas particulier de IOException, le FileNotFoundException. Si vous voulez dire à votre compilateur que c'est définitivement un Sub et non un Super déclarez simplement p comme Sub.

Dans ce cas, il est explicite non déclaré comme Sub mais comme Super donc tout Super ou ses fils peuvent se produire et lancer tout IOException qui pourrait ne pas être un FileNotFoundException ou l'un de ses enfants.

3
SchreiberLex 24 janv. 2017 à 15:18

Votre référence d'objet est de type Super, même si vous savez qu'il s'agit d'un objet Sub à l'exécution. Par conséquent, le compilateur vérifie la définition de la méthode du Super et vous donne cette erreur de compilation.

Ce ne serait pas différent d'obtenir l'erreur de compilateur suivante:

Object o = new String("Hello World");
o.charAt(2); //Obviously not allowed

Il est important de se rappeler que la clause throws fait partie de la définition de la méthode.

14
StuPointerException 15 août 2017 à 19:23

Le compilateur ne considère pas le type de l'objet, mais le type de référence que vous utilisez qui est Super.

En tant que Super.doStuff() throws IOException, c'est ce que vous devez attraper.

BTW, je recommande fortement d'utiliser un IDE, vous le trouverez plus productif.

5
Peter Lawrey 24 janv. 2017 à 11:32

C'est parce que vous utilisez un objet de type statique Super. Le compilateur ne peut pas savoir qu'au moment de l'exécution p pointe vers un objet Sub, il souhaite donc intercepter les exceptions levées par la méthode déclarée dans la classe Super

2
Michele Da Ros 24 janv. 2017 à 11:27