Java 不同接口中相同方法的冲突异常规范
在以下代码中:Java 不同接口中相同方法的冲突异常规范,java,exception,Java,Exception,在以下代码中: class MyException extends Exception{} interface Bread { public void eat() throws MyException; } interface Fringe { public void eat() throws RuntimeException; } public class Test implements Fringe , Bread // #5 { public static
class MyException extends Exception{}
interface Bread
{
public void eat() throws MyException;
}
interface Fringe
{
public void eat() throws RuntimeException;
}
public class Test implements Fringe , Bread // #5
{
public static void main(String[] args)
{
Fringe best = new Test(); // #1
best.eat();// #2
}
public void eat() throws RuntimeException // #3
{
System.out.println("Test");
throw new RuntimeException(); // #4
}
}
MyException
不是RuntimeException
。为什么我们可以将Test.eat()
声明为抛出RuntimeException
,而不是一般的异常
?这是因为在重写方法中,您只能抛出低于或等于合同中定义的异常的异常。因此,eat()
可以抛出MyException
及其子类,但不能抛出MyException
之上的任何内容,这就是Exception
的含义。运行时异常不是此规则的一部分,您可以自由抛出它们,因为它们未被“选中”
这是因为假设我正在使用Bread
接口访问Test
类的实例。如果我调用eat()
方法,我可以“检查”MyException,因为它是契约的一部分,但是如果底层实现决定抛出“更高”的异常,它将不会被捕获在我的MyException
catch块中,从而违反契约。查看以下代码以获取示例:
Bread b = new Test();
try {
// if this throws Exception, it won't be caught in the catch block
// thereby violating contract
b.eat();
} catch (MyException e) {
e.printStacktrace();
}
两点:
- 您不能将其声明为抛出
,因为它会抛出比Exception
接口中的Bread
方法指定的更一般的异常。从超类或接口继承的方法不能抛出比在超类或接口中指定的更一般的异常eat()
- 您可以将其声明为抛出
,因为无论是否在RuntimeException
子句中指定,方法都可以抛出未经检查的异常。(因此,指定它可以抛出throws
是多余的)RuntimeException
// Allowed because Test implements Bread
Bread obj = new Test();
如果现在调用obj.eat()
,编译器需要检查您是否正确处理该调用中可能发生的所有已检查异常。它通过查看变量obj
的类型来实现这一点,即Bread
。Bread
接口指定eat()
可以抛出MyException
(并且隐式地是MyException
的子类)
如果允许您的Test.eat()
方法抛出一种更一般的已检查异常,例如exception
,那么编译器无法仅通过查看obj
的类型来检查您是否正确处理了所有已检查的异常
为了防止这个问题,规则是不允许重写的方法抛出更一般的异常
重写方法只能抛出那些与重写方法中抛出的异常满足IS-A关系的异常
如果您试图在类中抛出Exception
,而接口抛出MyException
。。。编译器查看以下语句是否为真:
例外是——我的例外——你知道,它是假的。所以编译器拒绝了它
因此,您只能从子类中的方法引发更具体的异常
有关运行时异常的问题:
对于引发运行时异常,它相当于您没有显式编写它。所以编译器忽略了它。因为即使您没有提到它,方法也可以在运行时抛出异常
你确定这是正确的代码吗?MyException实际上并没有在这里的任何地方抛出。