看了这篇文章:
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
原始碼就是這個樣子,還是有省略的東西,把完整程式碼貼一下吧,按你程式碼現在這個樣子,你是沒把
Person girl = new Girl()
girl.speak()
這兩句應該放在main裡面,你直接在類別中調用,結構不對呀
黄舟2017-04-17 17:21:39
是變數的宣告型別決定了它能呼叫哪些方法,而不是它所指向的堆中的物件的實際型別。
像你這樣:
Person girl = new Girl();
girl.speak();
girl
的宣告類型是Person
,而Person
並沒有speak
這個方法,所以會報錯。注意是編譯器報的編譯期的錯誤,編譯器是不管你那個girl
執行的型別到底是什麼。 girl
的声明类型是Person
,而Person
并没有speak
这个方法,所以会报错。注意是编译器报的编译期的错误,编译器是不管你那个girl
执行的类型到底是什么。
运行期,虚拟机当然会知道girl
执行的堆中对象是Girl
类型。
编译器为什么要根据变量的声明类型来决定能不能调用某个方法?其中一个原因就是,编译期间可能根本不知道这个变量在运行期绑定的到底是什么类型的对象。举个例子:
Person p = Math. random() > 0.5 ? new Girl() : Boy();
这个例子中的p
girl
執行的堆中物件是Girl
類型。 🎜
🎜編譯器為什麼要根據變數的宣告類型來決定能不能呼叫某個方法?其中一個原因是,編譯期間可能根本不知道這個變數在運行期綁定的到底是什麼類型的物件。舉個例子:🎜
rrreee
🎜這個範例中的p
不到運作時根本無法確定它所綁定的物件的真實類型。 🎜ringa_lee2017-04-17 17:21:39
題主的問題涉及到了多態性概念。下面用題主的例子來說明:
假設使用主題定義的三個類別Person
、Girl
和Boy
。當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
定義一個物件ps
以後,它在編譯時的型別是Person
,而實際執行時間的型別是Girl
。
ps
這個物件時,程式只知道它是個Person
,而一個Person
只有eat
和speak
兩個方法,所以在呼叫物件成員的時候只能呼叫eat
和speak
兩個方法;程式不知道< code>ps物件的實際型別是Girl
,所以不能呼叫Girl
獨有的sing
方法。即:rrreee
那麼,既然程式並不知道ps
物件的實際動態類型是Girl
,為什麼ps.speak();
還能呼叫Girl
中的實作呢?這就是多態
的表現。 #🎜🎜# #🎜🎜#對於一個指向子類別的父類別指標/引用,如果子類別中重寫了父類別的方法,那麼在透過父類別指標/引用呼叫這個方法的時候,編譯器會在編譯時把這個父類別的方法呼叫動態綁定到實際類型的方法上去。而那些沒有被子類別重寫的方法,則會靜態綁定到父類別的方法上去。 #🎜🎜# #🎜🎜#這是從抽象角度來理解,更底層的實現方法就要參考具體實現了,在題主提供的文章中講的比較清楚。 #🎜🎜#