天天看點

Java Review (十一、面向對象----多态)多态性引用變量的強制類型轉換instanceof 運算符多态實作方式

文章目錄

多态是同一個行為具有多個不同表現形式或形态的能力。

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核心技術 卷一》