那一行是指
- 方法的重载版本是在编译时根据您传递的参数的编译时类型选择的;而
- 在运行时根据您调用每个方法的对象的类来选择覆盖的方法。
要理解这种区别,请考虑同时具有覆盖和重载的情况,如下所示。
public class Person {
}
---------------------------------------------------------
public class Postman extends Person {
}
---------------------------------------------------------
public class Dog {
public void barkAt(Person p) {
System.out.println("Woof woof");
}
public void barkAt(Postman p) {
System.out.println("Grrrr");
}
}
---------------------------------------------------------
public class Rottweiler extends Dog {
@Override
public void barkAt(Person p) {
System.out.println("I'm going to eat you.");
}
@Override
public void barkAt(Postman p) {
System.out.println("I'm going to rip you apart.");
}
}
在这种情况下,我们调用这些barkAt 方法之一,如下所示。
Dog cujo = new Rottweiler();
Person pat = new Postman();
cujo.barkAt(pat);
现在在这种特殊情况下,是编译器选择cujo.barkAt(pat); 是否调用public void barkAt(Person p) 或public void barkAt(Postman p) 之类的方法。这些方法是彼此的重载。
为此,编译器会查看传递给方法的表达式的类型,即变量pat。变量pat 的类型是Person,所以编译器选择了public void barkAt(Person p) 方法。
编译器不做的是选择被调用的是Rottweiler 类还是Dog 类中的方法。这发生在运行时,基于调用方法的对象的 class,而不是调用方法的变量的 type。 p>
所以在这种情况下,重要的是名为cujo 的对象的类。在这个例子中,cujo 是一个Rottweiler,所以我们得到了该方法的重写版本——在Rottweiler 类中定义的那个。
这个例子将打印出I'm going to eat you。
总结一下:
-
重载是在编译时根据参数type选择的。
-
覆盖是在运行时根据对象类选择的。
现在,可以使用强制转换来更改编译器对重载的选择。 不可能使用强制转换来更改覆盖的运行时选择。所以,我们可以写
cujo.barkAt((Postman) pat);
这一次,传递给方法的参数是Postman 类型的表达式。编译器相应地选择一个重载,这将打印I'm going to rip you apart.。