java中多型的經典問題分析
阿新 • • 發佈:2018-12-23
Question
package demo;
/**
* Created by zwj on 2016/3/26.
*/
class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
class B extends A {
public String show(B obj) {
return ("B and B");
}
public String show(A obj) {
return ("B and A");
}
}
class C extends B {
}
class D extends B {
}
public class ABCD {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println(a1.show(b)); // 1:a a
System.out.println(a1.show(c)); //2:a a
System.out.println(a1.show(d)); //3:a d
System.out.println(a2.show(b)); //4:b a
System.out.println(a2.show(c)); //5:b a
System.out.println(a2.show(d)); //6:a d、
System.out.println(b.show(b));//7:b b
System.out.println(b.show(c)); //8:b b
System.out.println(b.show(d)); //9:a d
}
}
分析
首先我們要明白一個道理,對於java中的多型是編譯看左邊,執行看右邊,方法在呼叫的時候會出現兩種情況,一種是過載,另一種是子類重寫。
過載
對過載來說,java在編譯時候由編譯器已經確定要呼叫的方法,也就是說編譯器根據兩個屬性來做處理,首先是呼叫者,還有就是方法引數,通過這兩個宗量就可以確定過載呼叫的方法,方法引數看傳入的變數的靜態型別,也就是宣告型別,不是看其實際型別。
重寫
對重寫來說,java編譯時候首先編譯器會根據呼叫關係,編譯生成相對位元組碼檔案,然後根據建立物件的實際型別去呼叫相對應的子類或者父類的方法。
- 第一條語句,A類沒有子類,執行第一條語句時候會去A中適應查詢所以 輸出為 A and A
- 跟第一條一樣。
- 當呼叫show(D) 時候,由於A類中有宣告顯示D的方法,所以直接呼叫相對的方法,而不會根據前兩條一樣去適應。也就是方法引數的所對應方法的選擇主要看靜態型別,也就是傳入引數的宣告型別。
- 第四條語句,首先我們查左邊,發現a2是A型別,所以會去A方法中查詢,這時候我們找到適應的方法,也就是show(A obj) 但執行時候我們發現a2是 B型別所以會呼叫B中的相對應重寫的方法,所以輸出為 B and A
- 原理同第四條。
- 由於B中沒有重寫 show(D obj)方法所以會呼叫A中的方法做處理,因此會輸出 A and D
- 直接呼叫自己方法
- 顯而易見
- 跟前面分析一樣
概括的說過載主要看傳入引數的左邊型別,重寫呼叫時候如果存在過載,則首先根據左邊型別看引數呼叫對應方法,然後再根據呼叫者的實際型別處理。