Java 編譯時多型和執行時多型
根據何時確定執行多型方法中的哪一個,多型分為兩種情況:編譯時多型和執行時多型。如果在編譯時能夠確定執行多型方法
中的哪一個,稱為編譯時多型,否則稱為執行時多型。
一、編譯時多型
方法過載都是編譯時多型。根據實際引數的資料型別、個數和次序,Java在編譯時能夠確定執行過載方法中的哪一個。
方法覆蓋表現出兩種多型性,當物件引用本類例項時,為編譯時多型,否則為執行時多型。例如,以下宣告p、m引用本類實例,呼叫toString()方法是編譯時多型。
public class Test { public static void main(String[] args) { Person p = new Person(); //物件引用本類例項 Man m = new Man(); //編譯時多型,執行Person類的toString() System.out.println(p.toString()); System.out.println(m.toString()); //編譯時多型,執行Man類的toString() } } class Person{ public String toString() { String name = "Person"; return name; } } class Man extends Person{ public String toString(){ String name = "Man"; return name; } }
二、執行時多型
1.當以下父類物件p引用子類例項時,p.toString)執行誰的setName()方法?
Person p = new Man();
p.toString();
Java支援執行時多型,意為p.toString()實際執行p所引用例項的toString(),究竟執行Person類還是Man類的方法,執行時再確定。如果Man類聲明瞭toString()方法,則執行之;否則執行Person類的toString()方法。
程式執行時,Java從例項所屬的類開始尋找匹配的方法執行,如果當前類中沒有匹配的方法,則沿著繼承關係逐層向上,依次
2.將上述例子中toString方法改為getName,因為在Object類中有toString類,無法測試Person與Man中所匹配的執行方法。
public class Test { //例子2 public static void main(String[] args) { Person p = new Man(); System.out.println(((Man) p).getName()); //返回結果為Man } } class Person{} class Man extends Person{ public String getName(){ String name = "Man"; return name; } }
此例中Person型別要引用Man類的例項,因Person中未定義setName()方法,故需要把Person類顯式地轉換為Man類,然後呼叫Man中的getName方法。
3.將例子1中Person和Man的方法名改為靜態的getName()方法,會返回什麼結果呢?
public class Test { //例子3
public static void main(String[] args) {
Person p = new Man();
System.out.println(p.type); //返回結果為P
System.out.println(p.getName()); //返回結果為Person
}
}
class Person{
String type = "P";
public static String getName() {
String name = "Person";
return name;
}
}
class Man extends Person{
String type = "M";
public static String getName(){
String name = "Man";
return name;
}
}
栗子中子類Man隱藏父類Person的屬性,而 Person p = new Man() 表示“先宣告一個Person類的物件p,然後用Man類對p進行例項化”,即引用型別為Person類,實際代表的是Man類。因此,訪問的是Person的屬性及靜態方法,詳細解釋如下。
所謂靜態,就是在執行時,虛擬機器已經認定此方法屬於哪個類。“重寫”只能適用於例項方法,不能用於靜態方法。對於靜態方法,只能隱藏,過載,繼承。
子類對於父類靜態方法的隱藏(hide),子類的靜態方法完全體現不了多型,就像子類屬性隱藏父類屬性一樣,在利用引用訪問物件的屬性或靜態方法時,是引用型別決定了實際上訪問的是哪個屬性,而非當前引用實際代表的是哪個類。因此,子類靜態方法不能覆蓋父類的靜態方法。
父類中屬性只能被隱藏,而不能被覆蓋;而對於方法來說,方法隱藏只有一種形式,就是父類和子類存在相同的靜態方法。
參考文獻:
Java程式設計實用教程