1. 程式人生 > >Java 編譯時多型和執行時多型

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從例項所屬的類開始尋找匹配的方法執行,如果當前類中沒有匹配的方法,則沿著繼承關係逐層向上,依次

在父類或各祖先類中尋找匹配方法,直到Object類。尋找p.toString()匹配執行方法的過程如下圖所示。

        因此,父類物件只能執行那些在父類中宣告、被子類覆蓋了的子類方法,如toString(),不能執行子類增加的成員方法。

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程式設計實用教程