1

我正在尝试编写一个异常处理程序类来处理流中的各种异常。业务流程会引发大量异常,并且处理程序具有将所有这些异常作为参数并进行所需处理的方法。我无法理解的行为是,当在业务流程中我只捕获异常(而不是特定的异常)然后将此捕获的异常实例传递给处理程序时,只调用了句柄(异常)而不是特定的处理程序用于特定异常的方法。以下代码片段将解释我的困惑。

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 块。

4

4 回答 4

3

这是关于 Java 中的静态与动态绑定。您可以利用动态调度(多态性)的唯一位置是方法调用中的点之前。括号内的任何参数都不受动态调度的影响,编译器会根据参数列表中声明的(静态)表达式类型选择一个明确的方法签名,该签名在运行时不能更改。

这是定义 Java 语言类型的基本特征:它是一种单一的调度语言,就像大多数其他 OOP 语言一样。Multiple-dispatch OOP 是一个完全不同的模型。例如,在这种情况下,每个人都假设的关于 OOP 的基本图景,即声明其方法的类,就会分崩离析:方法不属于任何特定的类,而是一个单独的实体。在您的特定情况下,该方法handle属于每个 Exception 类型和 Handler 类型一样多,并且在 Handler 中声明它没有多大意义。

于 2012-10-28T21:04:48.093 回答
2

为什么在第一种情况下对 Handler.handle 的调用会转到具有特定异常的特定方法。

在第一种情况下,您使用编译时类型的值调用它BException

new Handler().handle(new BException());

在第二种情况下,您使用编译时类型的值调用它Exception

catch (Exception e) {
   new Handler().handle(e);
}

基本上,您需要知道重载(选择的方法签名)发生在编译时......它只是在执行时发生的签名的实现(方法调用目标的继承层次结构的上下) .

于 2012-10-28T21:02:40.663 回答
1

这种行为是因为在您的 catch 块中,e变量具有 type 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);
    }
}
于 2012-10-28T21:01:52.723 回答
1

编译器将根据变量的编译时类型选择方法。您可以通过 instanceof 在运行时选择合适的方法。

于 2012-10-28T21:03:24.690 回答