java中的多态体现在重写和重载上,重载就属于静态分派,而重写属于动态分派。那我们先来弄清楚什么是静态类型,什么是动态类型。例如:
public class Son extends Father{}
Father a = new Son();
对于以上代码:Father属于静态类型,Son属于动态类型。
所谓静态类型是指在程序编译期间就完全确定,而动态类型则是在程序运行期间才可以确定。
下面,我们来看看一个静态分派的例子:
package fenixsoft;
public class StaticDispatch {
//父类
static abstract class Human{
}
//子类1
static class Man extends Human{
}
//子类2
static class Woman extends Human{
}
/*
* 三个重载的方法
*/
public void say(Human guy){
System.out.println("hello,guy");
}
public void say(Man guy){
System.out.println("hello,guy");
}
public void say(Woman guy){
System.out.println("hello,guy");
}
public static void main(String[] args){
StaticDispatch sd = new StaticDispatch();
Human man = new Man();
Human woman = new Woman();
sd.say(man);
sd.say(woman);
}
}
这是这个例子的输出结果:
hello,guy
hello,guy
下面我们来分析为什么会输出这样的结果:
由于动态类型在编译期间不可知,所以编译器在编译程序时并不知道纯金的参数的实际类型是什么,也就是说,在上面的例子中,编译器不知道man和woman的实际类型,所以编译器在重载时只能通过他们的静态类型来确定他们的类型。所以,java中重载时是通过参数的静态类型,而不是实际类型(动态类型)作为判断依据的。对于此例来说,他们的静态类型就是Human,所以输出了这个结果。
那我们再来看一个动态分派的例子:
package fenixsoft;
public class DynamicDispatch {
static abstract class Human{
protected abstract void say();
}
static class Man extends Human{
@Override
protected void say() {
// TODO Auto-generated method stub
System.out.println("man,hello");
}
}
static class Woman extends Human{
@Override
protected void say() {
// TODO Auto-generated method stub
System.out.println("woman,hello");
}
}
public static void main(String[] args){
Human man = new Man();
Human woman = new Woman();
man.say();
woman.say();
}
}
此例的输出如下:
man,hello
woman,hello
和静态分派相反,动态分派是通过对象的实际类型作为判断依据的。所以java中的重写是动态分派。就是在运行期间确定接受者的实例类型,将类方法中的符号引用解析到了不同的直接引用上,这就是方法重写的本质。