Java 覆盖情况下的异常
我们知道,在方法重写的情况下,如果子类方法抛出一些检查异常,那么强制父类方法应该抛出相同的检查异常或其父类异常,否则我们将得到编译错误。但没有关于未检查异常的规则 但如果假设Java允许父类方法检查异常,则该异常是子类方法检查异常的子类 有人能解释一下为什么Java中不允许这样做吗Java 覆盖情况下的异常,java,Java,我们知道,在方法重写的情况下,如果子类方法抛出一些检查异常,那么强制父类方法应该抛出相同的检查异常或其父类异常,否则我们将得到编译错误。但没有关于未检查异常的规则 但如果假设Java允许父类方法检查异常,则该异常是子类方法检查异常的子类 有人能解释一下为什么Java中不允许这样做吗 让我们换一种方式来回答这个问题: 你有甲级- class A { public void doStuff() throws SQLException { } } B类扩展了A类- class
让我们换一种方式来回答这个问题: 你有甲级-
class A {
public void doStuff() throws SQLException {
}
}
B类扩展了A类-
class B extends A {
public void doStuff() throws Exception {
}
}
由于违反了方法的约定,它将在编译期间引发异常
假设Java允许这样做,那么会有什么后果呢?如果覆盖没有抛出声明的方法,则可以抛出
RuntimeException
或没有声明的子类
class A {
public void run() {
}
}
class B extends A {
@Override
public void run() {
throw new RuntimeException("throw without declaration");
}
}
发件人:
RuntimeException
及其子类是未检查的异常。
未检查的异常不需要在方法或
构造函数的throws子句,如果可以通过执行
方法或构造函数,并在方法或
构造函数边界
throws
子句是方法签名的一部分,为了重写方法,重写方法必须具有与被重写方法相同的签名
因此,如果类B
扩展类A
和A
定义:
public void foo (int param) throws SomeException
{
....
if (something)
throw new SomeException ();
....
}
然后B
只能使用相同的签名覆盖foo:
public void foo (int param) throws SomeException
{
super.foo(param);
....
if (something)
throw new SomeOtherException ();
....
}
SomeOtherException
必须是SomeException
的子类,因为这是方法签名允许抛出的异常类型。如果重写方法试图抛出类型为SomeException
的超类的异常,则会违反该方法的约定
让我们声明一些异常类的类层次结构:
SuperException
SomeException
SomeOtherException
AnotherSomeException
您所建议的(Java允许父类方法检查异常,它是子类方法检查异常的子类
)将允许子类中的重写方法抛出任何类型为SuperException
的异常,这将允许它抛出另一个异常
。这违反了方法的签名,因为另一个SomeException
不是SomeException
的子类
来扩展我的评论,让我们考虑一下如果java允许你提出什么会发生什么。 假设类
C
有一个方法bar
,该方法接受类a
的实例,并调用该方法foo
public class C
{
....
public void bar (A a)
{
try {
a.foo ();
}
catch (SomeException ex) {
....
}
}
}
由于
foo
被声明为抛出SomeException
,因此调用foo
的任何代码都必须处理此异常或声明它可能抛出此异常。现在,如果Java允许B
重写foo
,但将其声明更改为public void foo()抛出异常
,那么B
中foo
的实现可能抛出异常的任何子类。由于bar
甚至不知道B
存在,因此它不知道必须捕获除SomeException
及其子类以外的任何异常。因此,编译器不能将此代码标记为错误,但如果bar
的调用者将B
的实例传递给它,则该代码仅在运行时无效,因为它可能抛出一个既不被bar
捕获也不声明的已检查的expetion。这就是为什么Java不允许您在重写方法时更改throws
子句的原因。我想您是在问为什么我不能这样做:
class Parent {
void doStuff() throws FileNotFoundException {
}
}
class Child extends Parent {
@Override
void doStuff() throws IOException {
}
}
这很简单,当我这样做时会发生什么:
final Parent parent = new Child();
try {
parent.doStuff();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
然后孩子决定扔一个,比如说
一、 正确地,尝试从调用parent.doStuff
捕获FileNotFoundException,但这不会捕获SocketException
我如何有一个未捕获的检查异常。这是不允许的
如果我特别尝试捕获SocketException,这将导致编译器错误,因为SocketException
未声明为从父.doStuff抛出
在一般情况下解决此问题的唯一方法是始终
捕获异常
,因为任何子类都可以声明它抛出更一般的类型并绕过my捕获
。这显然不理想。如果未在父类中指定已检查的异常,则重写方法无法引发该异常。原因是,您希望能够在可以传递超类型的任何位置使用子类型的实例,即,您的子类型需要以与超类型相同的方式行为。但是,如果您的子类型可以引发异常,则它的行为方式不同:它可以引发异常。对于未检查的异常也是如此,但是,正如名称已经告诉我们的那样,编译器没有检查它们,因此这只是没有静态增强
我建议你看一看这本书
关于为什么子类在超类承诺不抛出异常的情况下抛出异常是不好的示例:
class Animal {
void eatMeat() {System.out.println("eating meat");}
}
class Zebra extends Animal {
void eatMeat() throws IsVegetarianException {throw new IsVegetarianException(); }
}
嗯。。。也许你的
斑马
不是动物,或者动物
的界面太宽了。也许不是所有的动物都吃肉。顺便说一下:这发生在各种Java集合接口中。他们通过抛出未检查的NotSupportedException
来解决这个问题,但这只是设计中的一个缺陷,除了更改设计之外,没有其他好的解决方案 我可能不正确,但我想你是在问为什么超类A不能扩展扩展类A的子类B
这不可能存在,因为不清楚哪一个是父类。Beca
class A {
public void doStuff() throws Exception {
}
}
class B extends A {
public void doStuff() throws SQLException {
}
}