看了这篇文章:
https://www.ibm.com/developerworks/cn/java/j-lo-polymorph/
有一些疑问。
class Person {
public String toString(){
return "I'm a person.";
}
public void eat(){}
public void speak(){}
}
class Boy extends Person{
public String toString(){
return "I'm a boy";
}
public void speak(){}
public void fight(){}
}
class Girl extends Person{
public String toString(){
return "I'm a girl";
}
public void speak(){}
public void sing(){}
}
//最后这么用的话,
Person girl = new Girl();
girl.speak();
按照作者的说法,girl引用变量指向堆中的 Girl对象,所以运行的时候知道当前对象是Girl对象,找Girl的方法表,
找到后执行。这对于speak方法来说是行得通的。
但是如果这样呢:
girl.sing();
按照作者的说法,去Girl方法表找到sing方法,然后执行。
实际情况大家都知道有错误,编译不通过。
这中间肯定漏了点我不知道的什么?希望可以赐教。
换个方式问也就是:
当发生向上转型的时候,栈和堆中分别发生了什么?
是变量的声明类型决定了它能调用哪些方法,而不是它指向的堆中的对象的实际类型。
像你这样:
girl
的声明类型是Person
,而Person
并没有speak
这个方法,所以会报错。注意是编译器报的编译期的错误,编译器是不管你那个girl
执行的类型到底是什么。运行期,虚拟机当然会知道
girl
执行的堆中对象是Girl
类型。编译器为什么要根据变量的声明类型来决定能不能调用某个方法?其中一个原因就是,编译期间可能根本不知道这个变量在运行期绑定的到底是什么类型的对象。举个例子:
这个例子中的
p
不到运行时根本没法确定它绑定的对象的真实类型。