代碼定義java
class Father { public String name; public void out(){ System.out.println("father"); } public void drink(){ System.out.println("father drink"); } } public class Son extends Father { private String name ; public void out(){ System.out.println("son"); } public static void main(String[] args) { Father father = new Son(); father.name = "lisi"; System.out.println(father.name); father.out(); father.drink(); Son son = (Son)father; son.out(); System.out.println(son.name); } }
結果
lisi
son
father drink
son
nullc++
發現用父對象引用子實例後,方法能夠調用子類對象,可是屬性並不能爲子類對象賦值。
後來經過反編譯後獲取以下編譯結果性能
public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=3, args_size=1 0: new #5 // class example/Son 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: ldc #7 // String lisi 11: putfield #8 // Field example/Father.name:Ljava/lang/String; 14: aload_1 15: invokevirtual #9 // Method example/Father.out:()V 18: aload_1 19: invokevirtual #10 // Method example/Father.drink:()V 22: aload_1 23: checkcast #5 // class example/Son 26: astore_2 27: aload_2 28: invokevirtual #11 // Method out:()V 31: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 34: aload_2 35: getfield #12 // Field name:Ljava/lang/String; 38: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 41: return LineNumberTable: line 24: 0 line 25: 8 line 26: 14 line 27: 18 line 28: 22 line 29: 27 line 30: 31 line 31: 41
能夠看到11行在設置name屬性值的時候,仍然用的是父類對象,和父類對象中的name屬性,因此在強轉子類後,獲取name屬性爲空。
方法也一樣如此,第15行調用father.out方法時,也用的是父類對象,以及父類對象中的out方法,可是打印結果倒是son,是由於invokevirtural這個指令的問題,後來查閱的知,類在編譯完成後會生成一張虛方法表,存儲對應子類的方法調用,虛方法配合虛方法表完成多態的功能。
可是屬性就沒有這種功能了,屬性經過本地變量表的方法簽名,去獲取屬性和設置屬性,跟實際對象已經無關,只和左值類型有關
虛方法在使用時會消耗虛擬機性能,若是想減小虛方法的使用能夠用final修飾,或者採用靜態方法,也不要過度糾結性能,根據業務場景和性能寫出合適代碼。
java的實現多態和c++實現多態有些許類似,藉助c++代碼能夠更好的瞭解虛擬機幫咱們作了什麼操做,如下兩個代碼塊的方法,區別是virtural關鍵字
在父類方法中加入virtual關鍵字,就會調用實際類型的方法
去掉virtual關鍵字,就會根據聲明的指針類型,調用方法,不會去管實際類型指針
class Parent { public: string name = "10"; virtual void print() { cout << "parent" << endl; } }; class Son : public Parent { public: string name = "20"; virtual void print() { cout << "son" << endl; } }; int main() { Parent* p = new Son(); cout<< p->name<< endl; p->print(); auto son = ((Son*)p); cout << son->name << endl; son->print(); system("pause"); return 1; } 結果 10 son 20 son
class Parent { public: string name = "10"; void print() { cout << "parent" << endl; } }; class Son : public Parent { public: string name = "20"; void print() { cout << "son" << endl; } }; int main() { Parent* p = new Son(); cout<< p->name<< endl; p->print(); auto son = ((Son*)p); cout << son->name << endl; son->print(); system("pause"); return 1; } 10 parent 20 son