虽然关于多态的介绍都很清楚,但对于一些细节上的问题仍不是很清楚,为便于理解,网上找了一个例子并进行了修改。
先看一个例子:
package baseText;
class Animal {
public void eat(){
System.out.println("eat method in Animal");
}
}
class Horse extends Animal{
public void eat(){
System.out.println("eat method in Horse");
}
public void buck(){}
}
public class DuoTai{
public static void main(String[] args) {
Animal b = new Horse();
b.eat();
// b.buck();//编译不能通过
DuoTai dt = new DuoTai();
dt.doStuff(b);
}
public void doStuff(Animal a){
System.out.println("In the Animal version");
}
public void doStuff(Horse h){
System.out.println("In the Horse version");
}
}
输出结果是:
eat method in Horse
In the Animal version
原因解释:
从内存的角度去考虑, b其实就是一个Animal类型引用变量,它存放在栈中,因为是一个变量,所以他可以引用放在堆中的对象。然而一个引用变量有如下的特性:引用变量可以引用具有与所声明引用相同类型的对象,更重要的一点----
他可以引用所声明类型的任何子类型!!!(这一点可以说是java能够实现多态的重要支持)
因此我们可以这样理解下面这个语句:
Animal b = new Horse(); 在栈中声明了一个Animal类型的引用变量b,在堆中创建一个Animal子类Horse类型的对象,b引用了这个对象。
b.eat(); 在运行过程中JVM发现b引用的实际对象是Horse对象,因此调用的是Horse中的方法。
有一点需要记住,当使用指向Animal的引用时,编译器将只允许调用Animal类中的方法,因此 b.bulk()这个语句就不能通过编译了。
用方法doStuff()传递的不是一个对象,而是持有该对象的一个引用的一个副本。因此在这个程序中说明持有new Horse()这个对象的引用是一个Animal类型,所以那个animalRefToHorse它应该是一个Animal类型的。