确定编译时多线程异常类型

2022-09-04 22:05:15

我构建了一些我并不真正理解的东西 - 我不知道它是如何工作的。我已经熟悉了这篇多通道解释文章

请考虑以下两个异常和代码:

public class MyException1 extends Exception {
  // constructors, etc
  String getCustomValue();
}

public class MyException2 extends Exception {
  // constructors, etc
  String getCustomValue() { return "foo"; }
}

try {
  //...
} catch (MyException1|MyException2 e) {
  e.getCustomValue(); // won't work, as I expected
}

即使方法是相同的,我也无法调用,因为在Java中,上面的内容实际上应该将转换为(这就是我理解文档的方式)。getCustomValue()try/catchMyException1/2Exception

但是,如果我引入这样的界面:

public interface CustomValueGetter {
  String getCustomValue();
}

public class MyException1 extends Exception implements CustomValueGetter /*...*/
public class MyException2 extends Exception implements CustomValueGetter /*...*/

并将其添加到两个例外中,Java实际上能够允许我使用该方法。然后调用它是有效的:

try {
  //...
} catch (MyException1|MyException2 e) {
  e.getCustomValue(); // does work
}

简而言之,我的问题是:这里实际发生了什么:.(MyException1|MyException2 e)

什么是 e

  • 是否选择最接近的超类作为 的类型?这个问题问了这个问题,据说这就是答案。如果是这样,那么为什么当我访问e时,CustomValueGetter接口是“可见的”?在我的情况下,如果它是.eeException

  • 如果不是,如果真正的类是其中之一,或者为什么我不能简单地调用可用于这两个类的相同方法?MyException1MyException2

  • 一个动态生成的类的实例,它实现了两个异常的所有公共接口,并且是最接近的公共supperclass类型?e


答案 1

正如Ishuetze所说,e正在寻找两个例外共享的类或接口。在你的第一个示例中,尽管 Exception 类找不到共享类,因此它只能使用它提供的方法。

将示例更改为此代码将能够再次编译。

public class MyException12 extends Exception {
    public String getCustomValue(){ return "boo"; };
}

public class MyException1 extends MyException12{
    public String getCustomValue() { return "foo"; };
}

public class MyException2 extends MyException12{
    // constructors, etc
    public String getCustomValue() { return "foo"; };
}

与接口的示例一样,异常通知两者都有,因此能够使用它的功能。MyException1MyException2MyException12

这是一个SO问题,回答整个问题以及e的类型是什么。

答案中链接的引用:

更改异常类型的处理会以两种方式影响类型系统:除了对所有类型执行的常规类型检查之外,异常类型还要进行额外的编译时分析。出于类型检查的目的,使用析取声明的 catch 参数具有类型 lub(t1, t2, ...)(JLSv3 §15.12.2.7)其中 ti 是异常类型,则声明要处理的 catch 子句。非正式地说,lub(最小上限)是所讨论类型的最具体的超类型。对于多捕获异常参数,所讨论类型的最小上限始终存在,因为所有捕获的异常的类型必须是 Throwable 的子类。因此,Throwable是所讨论类型的上限,但它可能不是最小上限,因为Srowtable的某些子类可能是所讨论类型的超类(因此也是超类型),并且所讨论的异常类型可能实现公共接口。(lub 可以是超类和一个或多个接口的交集类型。出于异常检查 (JLSv3 §11.2) 的目的,重新抛出最终或有效最终 catch 参数的 throw 语句 (JLSv3 §11.2.2) 被视为精确地引发以下异常类型:


答案 2

在第一个代码示例中,Java无法自动推断,认为两者都实现了函数。因此,两者的类型层次结构中最大的公分母是;即 和不具有 函数 。因此,它不起作用。MyException1MyException2getCustomValueeExceptiongetCustomValue

Java是强类型的,尽管函数被命名为相似,但它与它们在同一类型中声明的不一样。

在第二个代码中,两个异常都实现了 。因此,是实现 的最大公分母。CustomValueGettereCustomValueGettergetCustomValue