文章目錄
多态是同一個行為具有多個不同表現形式或形态的能力。
Java 引用變量有兩個類型 :一個是編譯時類型,一個是運作時類型,編譯時類型由聲明該變量時使用的類型決定,運作時類型由實際賦給該變量的對象決定,如果編譯時類型和運作時類型不一緻,就可能出現所謂的多态(Polymorphism)。
多态執行個體
class BaseClass {
public int book = 6;
public void base() {
System.out.println("父類的普通方法");
}
public void test() {
System.out.println("父類的被覆寫的方法");
}
}
public class SubClass extends BaseClass {
// 重新定義一個 book 執行個體變量隐藏父類 book 執行個體變量
public String book = "子類書籍 ";
public void test() {
System.out.println(" 子類的覆寫父類的方法");
}
public void sub() {
System.out.println("子類的普通方法 ");
}
public static void main(String[] args) {
// 下面編譯時類型和運作時類型完全一樣 是以不存在多态
BaseClass bc = new BaseClass();
// 輸出
System.out.println(bc.book);
// 下面兩次調用将執行 BaseClass的方法
bc.base();
bc.test();
// 下面編譯時類型和運作時類型完全 樣,是以不存在多态
SubClass sc = new SubClass();
// 輸出 輕量級 Java EE 企業應用實戰"
System.out.println(sc.book);
// 下面調用将執行從父類繼承到的 base ()方法
sc.base();
// 下面調用将執行目前類的 test ()方法
sc.test();
// 下面編譯時類型和運作時類型不 樣,多态發生
BaseClass ploymophicBc = new SubClass();
// 輸出表明通路的是父類對象的執行個體變量
System.out.println(ploymophicBc.book);
// 下面調用将執行從父類繼承到的 base ()方法
ploymophicBc.base();
// 下面調用将執行目前類的 test ()方法
ploymophicBc.test();
// 因為 ploymophicBC 的編譯時類型是 BaseClass
// BaseClass 類沒有提供 sub ()方法,是以下面代碼編譯時會出現錯誤
// plonophicBc.sub()
}
}
結果:
6
父類的普通方法
父類的被覆寫的方法
子類書籍
父類的普通方法
子類的覆寫父類的方法
6
父類的普通方法
子類的覆寫父類的方法
- 父類引用指向子類對象時,多态發生了
引用變量在編譯階段隻能調用其編譯時類型所具有的方法,但運作時則執行它運作時類型所具有的方法 。是以,編寫 Java 代碼時,引用變量隻能調用聲明該變量時所用類裡包含的方法。 例如,通過 Object p = new Person()代碼定義一個變量 ,則這個變量隻能調用Object 類的方法,而不能調用 Person 類裡定義的方法
編寫Java程式時,引用變量隻能調用它編譯時類型的方法,而不能調用它運作時類型的方法,即使它實際所引用的對象确實包含該方法。如果需要讓這個引用變量調用它運作時類型的方法,則必須把 它強制類型轉換成運作時類型,強制類型轉換需要借助于類型轉換運算符。
類型轉換運算符是小括号,類型轉換運算符的用法是:(type)variable,這種用法可以将variable變量轉換成一個type類型的變量。類型轉換運算符可以将一個基本類型變量轉換成另一個類型。
除此之外,這個類型轉換運算符還可以将一個引用類型變量轉換成其子類類型。這種強制類型轉換不是萬能的,當進行強制類型轉換時需要注意:
- 基本類型之間的轉換隻能在數值類型之間進行,這裡所說的數值類型包括整數型、字元型和浮 點型。但數值類型和布爾類型之間不能進行類型轉換。
- 引用類型之間的轉換隻能在具有繼承關系的兩個類型之間進行,如果是兩個沒有任何繼承關系 的類型,則無法進行類型轉換,否則編譯時就會出現錯誤。如果試圖把一個父類執行個體轉換成子 類類型,則這個對象必須實際上是子類執行個體才行(即編譯時類型為父類類型,而運作時類型是子類類型),否則将在運作時引發ClassCastException異常。
下面是進行強制類型轉換的示範程式。下面程式詳細說明了哪些情況可以進行類型轉換,哪些情況不可以進行類型轉換。
引用類型強制轉換執行個體
public class ConversionTest {
public static void main(String[] args) {
double d = 13.4;
long l = (long) d;
System.out.println(l);
int in = 5;
//試圖把 個數值類型的變量轉換為 boolean 類型,下面代碼編譯出錯
//編譯時會提示:不可轉換的類型
// boolean b = (boolean)in ;
Object obj = "Hello";
// obj 變量的編譯時類型為 Object,Object、String 存在繼承關系,可以強制類型轉換
//而且 obj 變量的實際類型是 String ,是以運作時也可通過
String objStr = (String) obj;
System.out.println(objStr);
// 定義一個 objpri 變量,編譯時類型為 bject ,實際類型為 Integer
Object objpri = Integer.valueOf(5);
// objpri 變量的編譯時類型為 Object, objPr的運作時類型為 Integer
// Object Integer 存在繼承關系
// 可以強制類型轉換,而 objpri 變量的實際類型是 Integer
// 是以下面代碼運作時引發 ClassCastException 異常
//String str = (String)objPri;
}
}
當把子類對象賦給父類引用變量時,被稱為向上轉型( upcasting ),這種轉型總是可以成功的,這也從另一個側面證明了子類是一種特殊的父類 。這種轉型隻是表明這個引用變量的編譯時類型是父類,但實際執行它的方法時,依然表現出子類對象的行為方式。但把一個父類對象賦給子類引用交量時,就需要進行強制類型轉換,而且還可能在運作時産ClassCastException 異常,使用 instanceof 運算符可以讓強制類型轉換更安全。
instanceof運算符的前一個操作數通常是一個引用類型變量,後一個操作數通常是一個類(也可以是接口),它用于判斷前面的對象是否是後面的類,或者其子類、實作類的執行個體。如果是,則傳回true,否則傳回false。
在使用instanceof運算符時需要注意:instanceof運算符前面操作數的編譯時類型要麼與後面的類相 同,要麼與後面的類具有父子繼承關系,否則會引起編譯錯誤。
下面程式示範了 instanceof運算符的用法。
instanceof運算符執行個體
public class InstanceTest {
public static void main(String[] args) {
// 聲 hello 時使用 Object 類,則 hello 的編譯類型是 Object
// Object 是所有類的父類,但 hello 量的實際類型是 String
Object hello = "Hello";
// String Object 類存在繼承關系,可以進行 instanceof 運算 傳回 true
System.out.println(" 字元串是否是 Object 類的執行個體" + (hello instanceof Object));
System.out.println("字元串是否是 String 類的執行個體:" + (hello instanceof String)); // 傳回 true
// Math Object 類存在繼承關系,可以進行 instanceof 運算。傳回 false
System.out.println("字元串是否是 Math 類的執行個體" + (hello instanceof Math));
// Stri 呵實作了 Comparable 接口,是以傳回 true
System.out.println("字元串是否是 Comparable 接口的執行個體" + (hello instanceof Comparable));
String a = "He llo";
// String 類與 Math 類沒有繼承關系,是以下面代碼編譯無法通過
// System.out.println( "字元串是否是 Math 類的執行個體" + (a instanceof Math));
}
}
- 重寫
- 接口
- 抽象類和抽象方法
參考:
【1】:《瘋狂Java講義》
【2】:
https://www.runoob.com/java/java-polymorphism.html【3】:《Java核心技術 卷一》