multi-catch 块中异常问题的引用类型

reference type of exception issue in multi-catch block

e 是 Exception 类型,但在下面的代码中打印 Exception1:

class Exception1 extends IOException {void info(){}}
class Exception2 extends Exception {}

class TestMultiCatch {
    public static void main(String args[]) {
        try {
            int a = 10;
            if (a <= 10)
                throw new Exception1();
            else
                throw new Exception2(); 
        } catch (Exception1 | Exception2 e) {
            e.info();  //line 1 error "The method info() is undefined for type Exception"
            System.out.println(e);   //prints Exception1 (after commenting line 1)
        }
    }
}

根据我的研究 "e" 应该是 Exception 类型,它是 Exception1 和 Exception2 的公共基础 class。确实如此,从第 1 行的消息可以看出。

但是为什么:

System.out.println(e); //prints Exception1 and not Exception
System.out.println(e instanceof IOException); //prints true and not false
System.out.println(e instanceof Exception1); //prints true and not false
System.out.println(e instanceof Exception2); //false

? 谢谢

当您使用 multi-catch 子句catchException1 | Exception2 e 形式)时,e 的编译时类型是这两种类型共有的最大类型,因为当然代码必须处理任何一种类型 exception.From the spec:

An exception parameter may denote its type as either a single class type or a union of two or more class types (called alternatives). The alternatives of a union are syntactically separated by |.

A catch clause whose exception parameter is denoted as a single class type is called a uni-catch clause.

A catch clause whose exception parameter is denoted as a union of types is called a multi-catch clause.

...

The declared type of an exception parameter that denotes its type as a union with alternatives D1 | D2 | ... | Dn is lub(D1, D2, ..., Dn).

...其中 lub 是定义的最小上限 here.

如果您想使用任何特定于 Exception1Exception2 的内容,请使用单独的 catch 块:

} catch (Exception1 e) {
    // Something using features of Exception1
} catch (Exception2 e) {
    // Something using features of Exception2
}

如果 info 存在于 Exception1Exception2 上,重构它们以便 info 存在于它们的共同祖先 class 上:

class TheAncestorException extends Exception {
    public void info() { // Or possibly make it abstract
        // ...
    }
}
class Exception1 extends TheAncestorException {
    // Optionally override `info` here
}
class Exception2 extends TheAncestorException {
    // Optionally override `info` here
}

...所以编译器可以给 e 类型 TheAncestorException 并使 info 可访问。

catch (Exception1 | Exception2 e) {....}

这里e是Exception1和Exception2的引用变量。所以在编译时 e.info(); 将抛出异常,因为 info() 不存在 Exception2.

最好为每个使用单独的 catch 块,因为两者 类 没有相同的方法 info()

} catch (Exception1 e) {
            e.info();  
            System.out.println(e);  
        } catch (Exception2 e) {
            System.out.println(e);
        }

multi-catch 似乎是你的问题。您(编译器)只能访问在共同祖先上定义的方法。当然,"e" 在运行时将是 Exception1,但编译器不能假定它,因为它也可能是 Exception2。最好为 Exception1 和 Exception2 创建一个 catch 块。