一、多態性
Java引用變量有兩個類型:一個是編譯時的類型,一個是運行時的類型,編譯時的類型由聲明該變量時的類型決定,運行時的類型由實際賦值給該變量的對象決定。如果編譯時類型和運行時類型不一致,就會出現所謂的多態。
先看一個父類Base和子類Sub的代碼,根據其結果做進一步分析:
public class Base {
public int book = 6;
public void base() { System.out.println(1); }
public void test() { System.out.println(2); }
}
public class Sub extends Base {
// 重寫父類的test方法
public String book = "Java瘋狂筆記";
public void test() { System.out.println(3); }
public void sub() { System.out.println(4); }
public static void main(String[] args) {
// 編譯時類型和運行時類型不同,多態發生
Base ploy = new Sub();
System.out.println(ploy.book); // 6
ploy.test(); // 3
ploy.base(); // 1
// 不能調用ploy.sub();
}
}
Base ploy = new Sub();
這句話表明對象ploy
編譯時類型是Base,而運行時是Sub。對於父類Base中沒有被子類覆蓋的方法,ploy
得到的是父類的值,比如ploy.book=6, ploy.base=1
;對於被覆蓋的方法,實際執行的就是子類中覆蓋掉父類方法,例如ploy.test=3
是子類中被重寫後的打印值。這就是多態!
Java允許把一個子類對象直接賦給一個父類引用變量,無需任何類型轉換,或者被稱爲向上轉型(upcasting),向上轉型由系統自動完成。
當把一個子類對象直接賦給父類引用變量,例如上面的Base ploy = new Sub();
對象ploy
編譯時類型是Base,而運行時是Sub。當運行時,其方法行爲總是像子類的行爲而不是父類的行爲。這將出現相同類型的變量,執行同一個方法時出現不同的行爲特徵,這就是多態。
引用變量在編譯階段只能調用其編譯時類型所具有的方法,但運行時則執行其運行時類型所具有的方法。例如Object p = new Person()
,p
只能調用Object
類中的方法而不能調用Person
類中的方法,但運行的時候首先看Person
類中有沒有此方法,有的話運行Person
類中的方法,沒有的話才運行Object
類中的方法。
與方法不同的是,對象的屬性不具備多態性。如上面ploy
變量輸出book
屬性時並不是輸出子類Sub
的,而是輸出父類的屬性。
二、引用變量的強制類型轉換
Java程序中引用變量只能調用其編譯時類型的方法,而不能調用其運行時類型的方法。如果要讓這個引用變量來調用它運行時類型的方法嗎,則必須把它強制類型轉換爲運行時類型,強制類型轉換需要藉助於類型轉換運算符。
強制類型轉換語法很簡單:(type) variable
,這種用法可以將variable
變量轉換爲一個type
類型的變量。
引用類型之間的轉換隻能把一個父類變量轉換成子類類型,如果是兩個沒有任何繼承關係的類型,則無法進行類型轉換。即編譯時類型爲父類類型,運行時類型是子類類型。舉個例子:
public class TestConversion {
public static void main(String[] args)
{
Object obj = "Hello";
// obj變量的編譯類型是Object,是String類型的父類,可以進行強制類型轉換
String objstr = (String) obj;
System.out.println(objstr);
// obj2變量的編譯類型是Object,是Integer類型的父類,可以進行強制類型轉換
// 但obj2運行時類型是Integer,所以下面程序會觸發ClassCastException異常
Object obj2 = new Integer(5);
String obj2str = (String) obj2;
System.out.println(obj2str);
}
}
考慮到進行強制類型轉換時可能出現異常,因此進行強制類型轉換之前應先通過instanceof
運算符來判斷是否可以成功轉換。例如可將代碼改爲:
if(obj2 instanceof String)
{
String obj2str = (String) obj2;
System.out.println(obj2str);
}
三、instanceof運算符
instanceof運算符使用格式:引用類型變量 instanceof 類;
用於判斷前面的對象是否是後面的類,或是其子類的實例。如果是則返回true
,否則返回false
。
public class TestInstanceof {
public static void main(String[] args)
{
Object str = "Hello";
System.out.println(str instanceof String); // true
System.out.println(str instanceof Object); // true
System.out.println(str instanceof Math); // false
// 下面程序無法編譯,運算符前面的數的編譯類型必須與後面的類相同或是後面類的父類
// System.out.println((String)str instanceof Math);
}
}