根据多态的特点,如果是方法,编译时看的是左边,运行时看的是右边。
Person p = new Student();
编辑的时候他会检查P中有没有say()方法,如果有就没问题,如果没有就会发生编译错误。
当运行的时候呢,执行的是Student对象中的say()方法 也就是你覆盖的。就是说运行的是等号右边的
所以你输出的是“为什么”。
先来说说无法通过编译的两句,在了解这以后对多态就有了进一步的了解。Animal dog = new Dog();在编译时,编译器会检查dog这个引用的类型:Animal;编译阶段编译器会认为它就是一个Animal类型,再来看我们没有通过编译语句:dog.name();编译器会去查找Animal这个类中是否有name这个方法。从Animal类的定义中,我们并没有看到name()方法,也就不指望编译器能通过了。这就告诉我们,多态的局限性,你只能使用父类中有的方法,子类特有的方法无法调用,因为编译阶段,子类对象还没哟产生,你无法预知子类对象有何种不同的方法。
解决了上述问题我们再来看输出结果为什么是这样的:cat.eat() ,这句能通过编译,cat引用去查找Animal类,发现有eat这个方法,但是输出的结果告诉我们,它实际调用的是Cat中的eat()方法,原因很简单。Animal cat = new Cat();这一句我们一分为二的看,左边和右边,左边类型是编译期类型,右边是运行期引用实际指向的对象。在编译期,cat引用是Animal类型,查找到eat()方法,运行时,创建的实际是Cat对象,就如同开始提到的实例(非静态)方法,依靠的是对象本身,这也就解释了为何输出的是上述结果。