1. 程式人生 > 實用技巧 >Java繼承中的多型

Java繼承中的多型

Java中有兩種形式可以實現多型:繼承和介面,本文關注繼承。

繼承中多型只是例項方法的多型,屬性和靜態方法不適用多型。或者說例項方法是動態繫結的,靜態方法和成員變數是靜態繫結的。

1.例項方法

class Base{
   void method(){
       System.out.println("Base method!");
    }
}

class Sub extends Base{
    void method(){
        System.out.println("Sub method!");
        System.out.println(var);
    }
} public class Test { public static void main(String[] args) { Base who = new Sub(); who.method(); }
}

結果

Sub method!

Java中只有private、static和final修飾的方法以及構造方法是靜態繫結。

a、private方法的特點是不能被繼承,也就是不存在呼叫其子類的物件,只能呼叫物件自身,因此private方法和定義該方法的類繫結在一起。 b、static方法又稱類方法,類方法屬於類檔案。它不依賴物件而存在,在呼叫的時候就已經知道是哪個類的,所以是類方法是屬於靜態繫結。 c、final方法:final方法可以被繼承,但是不能被重寫,所以也就是說final方法是屬於靜態繫結的,因為呼叫的方法是一樣的。  總結:如果一個方法不可被繼承或者繼承後不可被覆蓋,那麼這個方法就採用的靜態繫結。

2.成員變數

class Base{
    String var = "Base var";
}

class Sub extends Base{
    String var = "Sub var";
}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();
        System.out.println(who.var);
    }
}

結果

Base var

3.例項方法的多型是個例外。對於一個引用型別的變數,Java編譯器按照它的宣告的型別

來處理,一個父類型別的變數引用了子類例項,該變數不會主動轉為子類。

宣告的型別並非實際的型別

class Base{

}

class Sub extends Base{

    String subVar = "Sub var";
    void subMethod(){
        System.out.println("Sub submethod!");
    }

}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();

        who.subMethod(); X
        who.subVar; X

    }

who是Base型別,根本就沒有subMethod()方法和subVar屬性,直接報錯。

因此,最開始提到的1.例項方法(成員方法)的多型,其前提條件就是,子類的這個方法在父類中也有,即父類方法被重寫了。

因此,在 被呼叫方法在父類中宣告,也就是說被子類覆蓋的方法 的前提之下,父類變數指向子類的引用,優先呼叫子類(實際型別)的方法,子類找不到在父類中找。這也是多型實現的另一種說法或原因。

class Base{
    void method(){
       System.out.println("Base method!");
    }
}

class Sub extends Base{

}

public class Test {

    public static void main(String[] args) {
        Base who = new Sub();
        who.method();

    }

當虛擬機器建立子類的時候,會建立該子類的方法列表,同時包含父類的方法列表。同時虛擬機器會引數引用的實際地址,找到建立的這個子類物件,查詢方法列表,如果在子類物件中找到這個方法,就直接呼叫。

如果沒找到,就去查詢父類方法,呼叫父類的方法。

子類繼承了父類,獲得了父類的屬性和方法?應是,子類中有父類物件(子類的初始化會引發父類的初始化,當然這須在父類未被初始會之時),子類中super()可以構造父類,子類可以呼叫父類中的方法,即對方法有使用權,並非真實擁有,即所有權。