写这篇文章是因为在学Java的时候遇到了一个问题:
public class Test5 {
public static void main(String... args){
C o1 = new D();
o1.m(1.0f);
}
}
class C{
public void m(double x) {
System.out.println("C' m(double)");
}
}
class D extends C{
public void m(float x) {
System.out.println("D's m(float)");
}
}
一个小误区
在我先前的理解中,o1引用D的实例,所以自然应该在D的类中找形参为float的实现,这样想的话结果就是 D ′ s m ( f l o a t ) D's\ m(float) D′s m(float),但是跑了一下之后发现实际是 C ′ s m ( d o u b l e ) C's\ m(double) C′s m(double)。
正确思路
首先对o1类型的分析就有问题,o1引用D的实例没有问题,但是o1的类型并不是D,而是C。这里可以看成一个隐式转换:
C
o
1
=
(
C
)
n
e
w
D
(
)
;
C\ o_1\ =\ (C)new\ D();
C o1 = (C)new D();
也就是o1的变量类型是C,但是o1 instaceof D。
既然o1的类型是C,所以只能调用C类中的方法,也就是m(double)。
这个很好理解:
- C是父类,D是子类。C中“看不到”D中的方法m(float)
- 实参为1.0f,形参为double类型,可以做隐式转换(double x = 1.0f)不会报错
所以最终调用的是C中的m(double).
一点延伸
如果在C中再实现一个m(float)方法,结果又会如何?
答案变成了 D ′ s m ( f l o a t ) D's\ m(float) D′s m(float)。
这是因为C中实现了m(float)之后,相对于m(double)来说,实参1.0f会优先匹配float的。而C中的m(float)又被D中的m(float)覆盖了。