1. 程式人生 > >Java多型學習記錄

Java多型學習記錄

面向物件的三大特性:封裝、繼承、多型。從一定角度來看,封裝和繼承幾乎都是為多型而準備的。這是我們最後一個概念,也是最重要的知識點。

1.定義:

多型:指允許不同類的物件對同一訊息做出響應。即同一訊息可以根據傳送物件的不同而採用多種不同的行為方式。(傳送訊息就是函式呼叫)

2.實現多型的技術稱為:動態繫結(dynamic binding),是指在執行期間判斷所引用物件的實際型別,根據其實際的型別呼叫其相應的方法。

3.作用:消除型別之間的耦合關係。

4.現實中,關於多型的例子不勝列舉。比方說按下 F1 鍵這個動作,如果當前在 Flash 介面下彈出的就是 AS 3 的幫助文件;如果當前在 Word 下彈出的就是 Word 幫助;在 Windows 下彈出的就是 Windows 幫助和支援。同一個事件發生在不同的物件上會產生不同的結果。

5.下面是多型存在的三個必要條件,要求大家做夢時都能背出來!

多型存在的三個必要條件

一、要有繼承;

二、要有重寫;

三、父類引用指向子類物件。

6.多型的好處:

1)可替換性(substitutability):多型對已存在程式碼具有可替換性。例如,多型對圓Circle類工作,對其他任何圓形幾何體,如圓環,也同樣工作。

2)可擴充性(extensibility):多型對程式碼具有可擴充性。增加新的子類不影響已存在類的多型性、繼承性,以及其他特性的執行和操作。實際上新加子類更容易獲得多型功能。例如,在實現了圓錐、半圓錐以及半球體的多型基礎上,很容易增添球體類的多型性。

3)介面性(interface-ability):多 態是超類通過方法簽名,向子類提供了一個共同介面,由子類來完善或者覆蓋它而實現的。如圖8.3 所示。圖中超類Shape規定了兩個實現多型的介面方法,computeArea()以及computeVolume()。子類,如Circle和 Sphere為了實現多型,完善或者覆蓋這兩個介面方法。

4)靈活性(flexibility):它在應用中體現了靈活多樣的操作,提高了使用效率。

5)簡化性(simplicity):多型簡化對應用軟體的程式碼編寫和修改過程,尤其在處理大量物件的運算和操作時,這個特點尤為突出和重要。

7.Java中多型的實現方式:介面實現,繼承父類進行方法重寫,同一個類中進行方法過載。

8.Java中多型的分類:

在java中,多型大致可以分為以下幾種情況:

1)person為父類,student為子類。那麼:person p=new student();

2)fliable為介面,bird為實現介面的類,那麼:fliable f=new bird();

3)fliable為抽象類,bird為繼承fliable的類,那麼:fliablef=new bird();

多型時需要說明p宣告為父類的引用,但他實際為子類引用。但是他只能呼叫父類中的方法。如果子類中的方法覆蓋了父類方法,那麼將呼叫父類方法(虛方法呼叫)。介面多型也是同樣的,也許你會問,如果f要呼叫自己的方法,那豈不是出錯了?其實這裡也是方法的覆蓋,因為實現介面的子類肯定會實現介面中的方法, 所以此種情況下呼叫的是bird中的方法。但是如果bird有一個方法在介面中沒有定義,那麼f不能呼叫。

9.instanceof運算子:

java語言的多型機制導致了引用變數的宣告型別和其實際引用物件的型別可能不一致,再結合虛方法呼叫規則可以得出結論:宣告為同種型別的兩個引用變數呼叫同一個方法時也可能會有不同的行為。這裡就引入了instanceof運算子。

那麼如果我聲明瞭person p=new student();我想將p轉為student的可不可以?當然可以,但是就得強制轉換了(兒子想成為父親直接來,父親想成為兒子你就強來)。

通常在強制轉換時加上instanceof來判斷。

if(p instanceof student) { student s=(student)p;}

多型貫穿於java整個學習,比如在異常處理時寫catch語句,我們規定必須子類異常寫在前,父類異常寫在後。為什麼呢?原因就是多型了。我們的 catch語句格式:catch(Exception e)。java程式在產生異常時會自動生成一個異常物件,如果先產生一個子類異常,並且父類異常寫在前,那麼根據多型肯定會執行此catch語句,執行完 一條catch語句後將會跳出。

10.例項:

關於JAVA的多型性雖然自己也不是很懂,但是下面的這個例子讓我理解了一些:

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{}

class E

{

  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));   //①

   System.out.println(a1.show(c));   //②

   System.out.println(a1.show(d));   //③

   System.out.println(a2.show(b));   //④

   System.out.println(a2.show(c));   //⑤

   System.out.println(a2.show(d));  // ⑥

   System.out.println(b.show(b));    //⑦

   System.out.println(b.show(c));    //⑧

   System.out.println(b.show(d));    //⑨   

  }

}

(三)答案

         ①   A and A

         ②   A and A

         ③   A and D

         ④   B and A

         ⑤   B and A

         ⑥   A and D

         ⑦   B and B

         ⑧   B and B

         ⑨   A and D

*有個好心人的解答*

該問題的關鍵有兩點:

一是子類與父類的關係,二是過載方法的呼叫問題。

子類物件可以直接當成父類物件使用,但反過來就不可以。舉例來說,人是父類,學生是人的子類,所以學生物件一定具備人物件的屬性,但是人物件就未必具有學 生物件的特性。所以學生物件可以當做人物件來使用,但是人物件就不能當做學生物件使用。注意當把子類物件當成父類物件使用時,子類物件將失去所有的子類特 性,只保留與父類同名的屬性和方法(同名方法不僅是函式名相同,而且引數型別也要一樣,否則不予保留)。

一個類中如果定義了過載的方法,則系統在呼叫方法時,會根據引數的型別自動選擇呼叫合適的方法。



1) a1.shows(b),在A中沒有含有B類引數的方法,但是含有A類引數的方法,根據子類物件父類可用的原則,所以呼叫方法

public String show(A obj)...{return ("A and A");} 



2) a1.show(c),C類是B類的子類,而B類又是A類的子類,所以C類物件可以當製作A類物件使用。結果同上。



3) a1.show(d),根據引數型別直接呼叫A中的方法

 public String show(D obj)...{

           return ("A and D");}



4) a2.show(b),a2本來是一個B物件,但是將其賦給了A類變數,所以a2只保留了與父類A同名的屬性和方法。a2.show(b)呼叫B類中的保留的與父類同名同參方法

 public String show(A obj)...{

           return ("B and A");

    } 

5) a2.show(c),B類的保留方法中沒有C類引數方法,但是有含有C的父類B的引數方法,所以呼叫的方法

        public String show(A obj)...{

           return ("B and A");

    }

我覺得這樣解釋更合理:a2本來是類B的一個物件,但是又將值賦給了類A,C是B的子類,B是A的子類,因此a2保留了類B中與A同名的屬性和方法。

6) a2.show(d),呼叫的是A類中的

        public String show(D obj)...{

           return ("A and D");

    }

7) b.show(b),呼叫B類中的

        public String show(B obj)...{

           return ("B and B");

    }

8) b.show(c),B類中沒有C類引數的方法,但是有B類引數的方法,所以呼叫方法         

   public String show(B obj)...{

           return ("B and B");

    }

9) b.show(d),解釋同8