为什么允许它捕获Java中抛出的异常的子类型

为什么允许它捕获Java中抛出的异常的子类型,java,try-catch,Java,Try Catch,我在一本Java书中读到,“Java将不允许您为检查的异常类型声明catch块,而该异常类型可能无法由try类主体抛出” 到目前为止,这是有道理的 但现在我在问自己为什么这段代码会编译: try { throw new Exception(); } catch (IOException e) { } catch (Exception e) { } Java允许我捕获IOException,但很明显,try块永远不会抛出它 这个例子是否打破了Jav

我在一本Java书中读到,“Java将不允许您为检查的异常类型声明catch块,而该异常类型可能无法由try类主体抛出”

到目前为止,这是有道理的

但现在我在问自己为什么这段代码会编译:

    try {
        throw new Exception();
    } catch (IOException e) {
    } catch (Exception e) {
    }
Java允许我捕获
IOException
,但很明显,try块永远不会抛出它

这个例子是否打破了Java书中描述的规则

Java允许我捕获IOException,但显然它永远不会 被试块抛出

因为
Exception
IOException
更一般,所以编译器理解
Exception
也可以是
IOException

下面是一个相反的例子,说明如果您尝试
NumberFormatException
而不是
Exception

try {
    throw new NumberFormatException();
} catch (IOException e) {  // fail
} catch (Exception e) {
}

它之所以失败,是因为
NumberFormatException
并不比
IOException

一般。显然,对于一个读这段代码的程序员来说,这是显而易见的,但我猜编译器会像处理对声明为抛出
异常的方法的调用一样处理
throw
语句,在这种情况下,抛出的异常很可能是
IOException

对您来说可能很明显,但编译器只能在静态分析上花费那么多时间。考虑到停顿的问题,它永远不可能是完美的。类似Findbugs的东西可能会产生一个警告。您可能想了解关于死代码检测的类似线程:还请注意,当您希望“编译器更智能”时,您必须提供一个确切的规范来描述应该检测的内容。因为您不希望在某些Java编译器上编译相同的Java代码,而不希望在其他编译器上编译相同的Java代码。。当Java试图调用抛出
异常的方法时,它显然可以捕获它的所有子类型。。但在我的例子中,永远不可能捕捉到
IOException
,因为引发的唯一可能的异常来自类型
exception
本身。所以,Java不知道这一点有点令人困惑,不是吗?还是我错了?对于编译器来说,调用该块中的方法与不调用该块中的方法没有区别。它看到的只是一个
抛出异常的块。所以它必须假设它可以是它的任何子类。这里只看“签名”。@Bela先生,是的,编译器很懒惰,不费心区分这两种情况;它不仅可以通过记忆块中抛出的异常类,还可以通过记忆它是否也可以是子类来实现。但在我的例子中,唯一可能抛出的异常是来自类型
异常
。因此,在我的示例中,编译器可能更聪明,并且知道这一事实。还是我错了?@mrbela编译器没有那么聪明,它有一个逻辑可以遵循,逻辑是如果捕获的异常没有抛出的异常那么全局,编译器不会打扰它自己,并给你一个警告