Java繼承中的多型
阿新 • • 發佈:2020-09-13
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()可以構造父類,子類可以呼叫父類中的方法,即對方法有使用權,並非真實擁有,即所有權。