我正在尝试编写一个异常处理程序类来处理流中的各种异常。业务流抛出了很多异常,并且处理程序具有将所有这些异常作为参数并执行所需处理的方法。 我无法理解的行为是,在业务流程中,我只捕获Exception(不是特定的),然后将这个捕获的异常实例传递给处理程序,只调用handle(Exception)而不是特定的处理程序以特定异常为目的地的方法。以下代码片段将解释我的困惑。
public class Scrap {
public static void main(String[] args) {
try {
new Handler().handle(new BException());
throw new BException();
} catch (Exception e) {
new Handler().handle(e);
}
}
static class Handler {
public void handle(AException e) {
System.out.println(e.getClass());
System.out.println("AAE");
}
public void handle(BException e) {
System.out.println(e.getClass());
System.out.println("BBE");
}
public void handle(Exception e) {
System.out.println(e.getClass());
System.out.println("E");
}
}
static class AException extends Exception {
private static final long serialVersionUID = 1L;
}
static class BException extends Exception {
private static final long serialVersionUID = 1L;
}
}
输出结果为:
class Scrap$BException
BBE
class Scrap$BException
E
如果我添加另一个catch块:
try {
new Handler().handle(new BException());
throw new BException();
} catch (BException e) {
new Handler().handle(e);
} catch (Exception e) {
new Handler().handle(e);
}
然后输出是:
class Scrap$BException
BBE
class Scrap$BException
BBE
为什么在第一种情况下对Handler.handle的调用不会使用特定的异常方法。
另一件需要注意的事情是,如果我在第一个代码上添加一个强制转换,如
try {
new Handler().handle(new BException());
throw new BException();
} catch (Exception e) {
new Handler().handle((BException)e);
}
输出符合预期(与第二个片段相同)
我确信这个行为是有意的,我只需要指向那个记录的行为,也就是我遇到的问题,我的业务流程抛出~30个异常,因为这个行为我必须编写30个单独的catch块。 / p>
答案 0 :(得分:3)
这是关于Java中的静态与动态绑定。您可以利用动态调度(多态)的唯一位置是方法调用中的点之前。括号内的参数不受动态调度的影响,编译器会根据参数列表中声明的(静态)表达式类型选择一个在运行时不能更改的明确方法签名。
这是定义Java语言类型的基本功能:它是一种单一调度语言,就像大多数其他OOP语言一样。多分派OOP是一种完全不同的模型。例如,在这种情况下,每个人都假设有关OOP的基本图片,即声明其方法的类,都会分崩离析:一个方法不属于任何特定的类,并且是一个单独的实体。在您的特定情况下,方法handle
将与Handler类型一样属于每个Exception类型,并且在Handler中声明它没有多大意义。
答案 1 :(得分:2)
为什么在第一种情况下调用Handler.handle会使用特定的异常方法。
在第一种情况下,您使用编译时类型BException
的值调用它:
new Handler().handle(new BException());
在第二种情况下,您使用编译时类型Exception
的值调用它:
catch (Exception e) {
new Handler().handle(e);
}
基本上,您需要注意重载(选择的方法签名)发生在编译时 ...它只是在执行时发生的该签名的实现(在方法调用的目标的继承层次结构中上下)。
答案 2 :(得分:1)
这种行为是因为在您的catch块中,e
变量的类型为Exception
。您需要执行以下操作来更改基于handle()
类型调用的Exception
:
public static void main(String[] args) {
try {
new Handler().handle(new BException());
throw new BException();
} catch (AException e) {
new Handler().handle(e);
} catch (BException e) {
new Handler().handle(e);
}
}
答案 3 :(得分:1)
编译器将根据变量的编译时类型选择方法。您可以通过instanceof。
在运行时选择正确的方法