Java 确定编译时多批次异常类型
我建造了一些我并不真正理解的东西——我不知道它是如何工作的。我已经熟悉了这一点 考虑以下两种例外情况和代码:Java 确定编译时多批次异常类型,java,exception,try-catch,java-7,multi-catch,Java,Exception,Try Catch,Java 7,Multi Catch,我建造了一些我并不真正理解的东西——我不知道它是如何工作的。我已经熟悉了这一点 考虑以下两种例外情况和代码: public class MyException1 extends Exception { // constructors, etc String getCustomValue(); } public class MyException2 extends Exception { // constructors, etc String getCustomValue() {
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
}
即使方法相同,我也无法调用getCustomValue()
,因为在Java内部,上面的try/catch
实际上是将MyException1/2
转换为异常
(这就是我对文档的理解)
但是,如果我引入这样的接口:
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 | myException2e)
什么是e
?
- 是否选择最接近的超类作为
的类型?据推测,这就是答案。如果是这样,那么为什么当我访问e时CustomValueGetter接口“可见”?在我的例子中,如果e
是一个e
,就不应该这样异常
- 如果不是,如果真正的类是
或MyException1
为什么我不能简单地调用这两个类可用的相同方法MyException2
是否是动态生成的类的实例,该类实现了两个异常的所有公共接口,并且是最接近的公共SuperClass类型e
MyException1
和MyException2
都实现了函数getCustomValue
。因此,e
是两者类型层次结构中最大的公分母;这是异常
,没有函数getCustomValue
。因此,它不起作用
Java是强类型的,尽管函数的名称相似,但它与以相同类型声明的函数并不相同
在第二个代码中,两个异常都实现了
CustomValueGetter
。因此,e
是最大的公分母CustomValueGetter
,它实现了getCustomValue
,,正如Ischuetze所说,e正在寻找两个异常都共享的类或接口。在中的第一个示例中,尽管存在异常类,但无法找到共享类,因此它只能使用它提供的方法
将示例更改为此代码将能够再次编译
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"; };
}
与您的界面示例一样,异常通知MyException1
和MyException2
都具有MyException12
,因此能够使用其功能
这是一个很好的问题,回答了整个问题以及e的类型
答案中的链接引用:
更改异常类型的处理会以两种方式影响类型系统:除了对所有类型执行常规的类型检查之外,异常类型还要进行额外的编译时分析。为了进行类型检查,使用析取声明的catch参数具有类型lub(t1,t2,…)(JLSv3§15.12.2.7),其中ti是声明catch子句要处理的异常类型。非正式地说,lub(最小上界)是所讨论类型中最具体的超类型。在多捕获异常参数的情况下,所讨论的类型的最小上界始终存在,因为所有捕获的异常的类型都必须是Throwable的子类。因此,Throwable是相关类型的上限,但它可能不是最小上限,因为Throwable的某些子类可能是相关类型的超类(因此也是超类型),并且相关异常类型可能实现公共接口。(lub可以是超类和一个或多个接口的交叉类型。)为了进行异常检查(JLSv3§11.2),返回最终或有效最终捕获参数的抛出语句(JLSv3§11.2.2)被视为精确抛出以下异常类型:
挖掘@Kevin Eshche的JLS链接,我似乎找到了一个正确的答案 编译时
e
实际上是一个最小上界,它在中定义
文件摘录:
计算交叉点比一开始可能要复杂得多
认识到。假设类型参数被约束为超类型
泛型类型的两个不同调用,例如List和
列表中,原始交集操作可能会生成对象。
然而,更复杂的分析会产生一组包含
列表类似地,如果类型参数T被约束为
两个不相关的接口I和J的超类型,我们可以推断T必须
要客观,否则我们可能会得到一个更严格的I&J界限。这些问题
本节后面将更详细地讨论
简言之,它是所有
|'d异常(在我的例子中是异常
)中最接近的公共超类型的类
,并且它实现了所有异常所做的所有接口(在我的例子中是CustomValueGetter
和Serializable
)。如果你的答案中发布的链接的答案是正确的,那么我使用的接口永远不应该在e
中解析,因为这两个异常的超类都没有实现它。@Dariusz I edid并在另一个问题的答案中引用了链接,通知后面的部分说:lub可以是超类和一个或多个接口的交集类型。
太糟糕了,这一措辞没有纳入实际的Java语言文档(编写得非常模糊)。我想最接近的是对的描述,其中提到了“类型推断(§15.12.2.7)”,对的描述也是如此。