Java中的Java多态行为怪异,需要解释

时间:2012-10-28 20:59:57

标签: java exception-handling polymorphism

我正在尝试编写一个异常处理程序类来处理流中的各种异常。业务流抛出了很多异常,并且处理程序具有将所有这些异常作为参数并执行所需处理的方法。 我无法理解的行为是,在业务流程中,我只捕获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>

4 个答案:

答案 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。

在运行时选择正确的方法