日期:2014-05-20  浏览次数:20707 次

一个多态问题


class Father {
public void say() {
System.out.println("I am father!");
}

}

class Son extends Father {
@Override
public void say() {
System.out.println("I am son");
}
}

public class Test {

public void say(Father father) {
System.out.println("say1");
father.say();
}

public void say(Son son) {
System.out.println("say2");
son.say();
}

public static void main(String[] args) {
Father father = new Son();
new Test().say(father);
}
}


J2SE基础忘光了,为什么结果是
say1
I am son
而不是
say2
I am son
多态

------解决方案--------------------
引用:
Quote: 引用:

Quote: 引用:

Quote: 引用:

输入参数类型是 Father,父类能直接引用子类,子类无法直接引用父类。


没看明白


 new Test().say(father);
输入的是Father类型,自然会调用 public void say(Father father) 方法,如果你没写 public void say(Father father) 方法,只有一个public void say(Son son) 方法,编译器都通不过


确实,没有say(Father father)方法确实会编译就通不过,但是不能完全解释我有这个方法,我在运行一个声明为Father类型的实际为Son对象的时候,调用的是say(Father father),而不是say(Son son)。在运行时,入参不检查实际类型吗?

java在运行时才检测实际类型,编译器只看引用类型
------解决方案--------------------
要调用哪个重载方法是在编译时作出决定的,而选择被覆盖方法是在运行时进行的。
请楼主参考《Effective Java》一书第165页第41条:慎用重载,可以很好地解答楼主的问题。
本人菜鸟,只是刚好在看这本书,所以不能很好地用自己的语言进行回答。
------解决方案--------------------
这个问题说清楚,lz需要明白两个概念:静态编译和运行期的动态绑定。就是说因为你在程序中 Father father = new Son(); 将father声明成了Father类,这样在编译器就仅仅会将其当成Father,而不会关注其实际的子类是啥,所以编译器就绑到了第一个say()方法,就像有有LS说的,如果程序中没有
public void say(Father father) {
        System.out.println("say1");
        father.say();
    } 方法,程序会直接编译都通不过的;
而调用具体对象上的某一个方法,这就是运行期的动态绑定在起作用,就是说运行时,系统会得到对象的实际类(Son),然后调用实际类的方法。
------解决方案--------------------
如你定义一个Object,并且有它的子类,在编译时编译器不能确定你传入的实际对象是什么,但是它肯定是Object的子类的一个对象。所以编译时指定为Object才允许编译通过。
本例中,编译的时候只管Father father。编译器认为它就是个father,那就只能调用带有Father参数的方法,你调用带有Son的方法,你自己是知道的,但编译时编译器还不知道。。多态运用的是动态绑定机制,动起来才知道。。
实际在调用中发现你传入的Father对象可以转型为son,于是调用的是son里面的方法。
我是这么理解的。