你可能忽略的多型問題

weixin_34253539發表於2018-08-12

多型:多型通過分離做什麼和怎麼做,從另一角度將介面和實現分離出來,有些文章將過載視作編譯時多型(其實個人感覺並沒有多型的特性),將重寫視為執行時多型

先來看一段程式碼:

class Father {
    protected String type = "Father";

    public Father() {
    }

    public void getType() {
        System.out.println(type);
    }
}

class Son extends Father {
    protected String type = "Son";
    public Son() {
    }

    @Override
    public void getType() {
        System.out.println(type);
    }
}

public class TestDynamicBind {

    public void getType(Father father) {
        System.out.println("this is father interface");
        father.getType();
    }

    public void getType(Son son) {
        System.out.println("this is son interface");
        son.getType();
    }

    public static void main(String[] args) {
        Father son = new Son();
        System.out.println(son.type);   --1、Father
        son.getType();  -- 2、Son
        TestDynamicBind bind = new TestDynamicBind();
        bind.getType(son); -- 3、this is father interface/Son  
        bind.getType(new Son()); --4、this is son interface/Son  
    }
}
複製程式碼

程式的執行結果為:

Father
Son
this is father interface
Son
this is son interface
Son
複製程式碼
  • 1列印type屬性,注意域和靜態方法是無法使用多型的,因此列印域值為Father
  • 2通過物件的例項方法列印type屬性,雖然變數son的宣告型別為Father,但實際為Son型別物件,執行例項方法時會根據呼叫物件的方法表(如果物件為子類,改寫了父類的方法,那麼子類和父類的那些同名的方法共享一個方法表項,所有繼承父類的子類的方法表中,重寫的父類所定義的方法的偏移量也總是一個定值,這樣 JVM 在呼叫例項方法時只需要指定呼叫方法表中的第幾個方法即可)實際呼叫Son class的getType方法
  • 3呼叫TestDynamicBind的getType方法,注意該類有兩個getType方法(也就是包含兩個過載的getType方法),執行時應該調哪一個呢,其實編譯時就決定了(所以個人覺得並不具備多型的特性),因為執行時是根據引數型別決定呼叫方法的,而引數型別是編譯時期決定的,雖然物件實際為Son型別,後面會展示相關位元組碼,因此走入了getType(Father father)方法,但實際呼叫物件的getType方法時由於該物件為Son型別而呼叫了Son的getType方法,輸出Son
  • 4直接構造了new Son()物件傳入TestDynamicBind物件的getType方法,這種方式和Son son = new Son();bind.getType(son);的效果是一致的,因此走入了TestDynamicBind的getType(Son son)方法且輸出Son

上位元組碼

  • 上面是main方法的位元組碼,可以看到TestDynamicBind的兩次getType呼叫(後兩個標註)都是編譯期決定了引數型別(LFather/LSon),實際也確定了呼叫哪個方法,雖然位元組碼命令為invokevirtual
  • 對於物件例項方法的多型呼叫,繼承父類和實現介面的實現機制雖有不同(繼承的方法在父類和子類的方法表項的位置是相同的,而實現介面的方法在不同實現類的方法表項的位置很可能是不同的),但實際呼叫時都走了各自物件的具體實現方法

歡迎關注微信訂閱號

相關文章