多异常捕获子句中异常的静态类型是什么?

Nei*_*gco 5 java types

在这个代码示例中,ecatch 块中的静态类型是什么?

try {
    ....
} catch(IOException | NumberFormatException e) {
    //what's the static type of e in here? Is it Exception?
    System.out.println(e.getClass());
}
Run Code Online (Sandbox Code Playgroud)

它似乎有效Exception,但是当我在 IDE 中将鼠标悬停在它上面时,它说 IOException | NumberFormatException。这是一种仅适用于 catch 块中的多个异常的特殊类型还是推广到其他类型?

And*_*eas 5

TL;DR:静态类型是最接近的公共超类。


Java语言规范,第14.20 节。声明try

异常参数可以将其类型表示为单个类类型或两个或多个类类型的联合(称为替代项)。联合的替代项在语法上由 分隔|

异常参数catch表示为单个类类型的子句称为uni-catch子句

异常参数catch表示为类型联合的子句称为多重catch子句

用单个类类型表示其类型的异常参数的声明类型就是该类类型。

异常参数的声明类型,将其类型表示为与替代项 D 1 |的联合。D 2 | ... | D n为 lub(D 1 , D 2 , ..., D n )。

因此,它基本上被称为“联合类型”,并且在语言的其他地方不存在。


更新

有效类型是最接近的常见超类型(类和/或接口)的并集,即您可以调用所有替代方案通用的任何方法。

下面的代码说明了以下几点:

  • 由于这两个异常都扩展了SuperException,因此您可以调用该SuperException方法。
  • 由于这两个异常都实现了接口Foo,因此您可以调用该Foo方法。
  • 有效类型不是SuperException,因为那样你就不能调用Foo方法,它也不是Foo,因为那样你就不能调用SuperException方法。
  • 有效类型实际上是最接近的公共超类型的联合,这实际上意味着所有公共超类型。
try {
    // some code throwing the exceptions
} catch (SubException1 | SubException2 e) {
    e.methodInSuper();  // you can call the SuperException method
    e.foo();            // you can call the Foo method
}
Run Code Online (Sandbox Code Playgroud)
interface Foo {
    void foo();
}
class SuperException extends Exception {
    public void methodInSuper() {
        // code here
    }
}
class SubException1 extends SuperException implements Foo {
    @Override
    public void foo() {
        // code here
    }
}
class SubException2 extends SuperException implements Foo {
    @Override
    public void foo() {
        // code here
    }
}
Run Code Online (Sandbox Code Playgroud)

更新2

要回答确切的问题“异常的静态类型是什么?”,我们需要查看字节码。

上述代码的catch子句的字节码为:

        34: astore_1
        35: aload_1
        36: invokevirtual #33                 // Method SuperException.methodInSuper:()V
        39: aload_1
        40: checkcast     #38                 // class Foo
        43: invokeinterface #40,  1           // InterfaceMethod Foo.foo:()V
        48: return
      Exception table:
         from    to  target type
             0    34    34   Class SubException1
             0    34    34   Class SubException2
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,单个catch子句注册了 2 个要捕获的异常,将它们定向到同一代码块。呼叫SuperException.methodInSuper()直接完成。对 的调用Foo.foo()是在转换为 后完成的Foo。编译后的代码可以被认为等同于以下内容,只不过它只捕获 2 个子异常:

} catch (SuperException e) { // only catch SubException1 and SubException2
    e.methodInSuper();
    ((Foo) e).foo();
}
Run Code Online (Sandbox Code Playgroud)

结论:静态类型是最接近的公共超类。该超类未定义的任何其他公共接口都由编译器使用强制转换默默处理。