看了这篇文章:
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方法,然后执行。
实际情况大家都知道有错误,编译不通过。
这中间肯定漏了点我不知道的什么?希望可以赐教。
换个方式问也就是:
当发生向上转型的时候,栈和堆中分别发生了什么?
PHPz2017-04-17 17:21:39
The source code is like this, there are still some omitted things, please post the complete code. According to your code now, you didn’t
Person girl = new Girl()
girl .speak()
These two sentences should be placed in main. You call them directly in the class. The structure is wrong
黄舟2017-04-17 17:21:39
It's the variable's declared type that determines which methods it can call, not the actual type of the object in the heap it points to.
Like you:
Person girl = new Girl();
girl.speak();
The declaration type of girl
is Person
, and Person
does not have the speak
method, so an error will be reported. Note that this is a compile-time error reported by the compiler. The compiler does not care what type your girl
executes. girl
的声明类型是Person
,而Person
并没有speak
这个方法,所以会报错。注意是编译器报的编译期的错误,编译器是不管你那个girl
执行的类型到底是什么。
运行期,虚拟机当然会知道girl
执行的堆中对象是Girl
类型。
编译器为什么要根据变量的声明类型来决定能不能调用某个方法?其中一个原因就是,编译期间可能根本不知道这个变量在运行期绑定的到底是什么类型的对象。举个例子:
Person p = Math. random() > 0.5 ? new Girl() : Boy();
这个例子中的p
girl
is of type Girl
. 🎜
🎜Why does the compiler decide whether a method can be called based on the declared type of the variable? One of the reasons is that during compilation, it may not be known at all what type of object this variable is bound to at runtime. For example: 🎜
rrreee
🎜p
in this example cannot determine the true type of the object it is bound to until runtime. 🎜ringa_lee2017-04-17 17:21:39
The subject’s question involves the concept of polymorphism. Let’s use the example of the subject to illustrate:
Assume that the three classes Person
, Girl
and Boy
defined by the subject are used. When Person
、Girl
和Boy
。当
Person ps = new Girl();
定义一个对象ps
以后,它在编译时的类型是Person
,而实际运行时的类型是Girl
。
在使用ps
这个对象时,程序只知道它是个Person
,而一个Person
只有eat
和speak
两个方法,所以在调用对象成员的时候只能调用eat
和speak
两个方法;程序并不知道ps
对象的实际类型是Girl
,所以不能调用Girl
独有的sing
方法。即:
ps.eat(); // OK,调用父类实现
ps.speak(); // OK,调用子类实现
ps.sing(); // Error
那么,既然程序并不知道ps
对象的实际动态类型是Girl
,为什么ps.speak();
还能调用Girl
rrreee
After defining an object ps
, its type at compile time is Person
, but its actual runtime type is Girl
.
ps
object, the program only knows that it is a Person
, and a Person
only has eat
and < There are two methods code>speak, so when calling object members, only two methods eat
and speak
can be called; the program does not know ps
The actual type of the object is Girl
, so the unique sing
method of Girl
cannot be called. That is: rrreee
So, since the program does not know that the actual dynamic type of theps
object is Girl
, why can ps.speak();
still call Girl
? This is what polymorphism
looks like. 🎜 🎜For a parent class pointer/reference pointing to a subclass, if the parent class method is overridden in the subclass, then when this method is called through the parent class pointer/reference, the compiler will compile the parent class's Method calls are dynamically bound to methods of the actual type. Those methods that have not been overridden by subclasses will be statically bound to the methods of the parent class. 🎜 🎜This is understood from an abstract perspective. The lower-level implementation method must refer to the specific implementation, which is explained more clearly in the article provided by the subject. 🎜大家讲道理2017-04-17 17:21:39
The Stack is person, the heap is girl, and the person class has no reference to the sing method.