所以我想弄清楚为什么一个程序正在编译它的方式,希望你们能为我解释一下。
class Vehicle{
public void drive() throws Exception{
System.out.println("Vehicle running");
}
}
class Car extends Vehicle{
public void drive(){
System.out.println("Car Running");
}
public static void main(String[] args){
Vehicle v = new Car();
Car c = new Car();
Vehicle c2 = (Vehicle) v;
c.drive();
try {
v.drive();
} catch (Exception e) {
e.printStackTrace();
} //try v.drive()
try {
c2.drive();
} catch (Exception e) {
e.printStackTrace();
} //try c2.drive()
}
}
因此上述程序的输出将是
汽车行驶
汽车运行
汽车行驶
我的问题是,为什么我必须执行try / catch块来为v和c2对象调用drive()方法而不是c?他们都是Car的例子,所以这里发生了什么?
答案 0 :(得分:10)
Vehicle
有一个drive()
方法会引发异常。
Car
使用自己的Vehicle
方法覆盖Drive()
的{{1}}方法,该方法不会引发异常。
你得到输出的原因是因为即使Drive()
是car类型,编译器在编译时也不知道这个事实,所以当你调用Vehicle v
时编译器没有我知道你正在调用Car的v.drive()
方法。
假设您以下列方式实例化drive
:
v
编译时,你不知道v是否是汽车。在你运行程序之前你不会知道。
答案 1 :(得分:1)
重写方法可以更具体地说明它们返回和抛出的内容。它们可以使用返回对象和异常的子类,或者省略在父方法签名中声明的异常。当你调用((Vehicle)new Car())。drive()然后执行子程序的实现,但父进程的方法签名在编译时被使用,这会强制你捕获在Vehicle中定义的异常。
答案 2 :(得分:0)
我们有:
Vehicle v = new Car();
Car c = new Car();
Vehicle c2 = (Vehicle) v;
此时,v
和c2
为Vehicle
。这意味着您正在调用public void drive() throws Exception
Vehicle
。这就是为什么你需要对这些方法使用try / catch而不是c.drive()
的原因(因为该方法不会抛出异常)。
答案 3 :(得分:0)
其他答案解释了过度使用的方法;然而,还有另一个问题。你这么说:
他们都是Car的例子,所以这里发生了什么?
但是对于编译器来说,它们并不是Car的所有实例 - 编译器会查看变量的类型:
Vehicle v = new Car();
Car c = new Car();
Vehicle c2 = (Vehicle) v;
在编译时,v
被视为Vehicle
,c
被视为Car
,异常将被相应处理。在运行时,JVM知道v
实际上包含Car
,但那是不同的。