SCJP認證 第二章 面向對象 2.3多態性

目標

5.2 給定一個場景,編寫代碼,演示多態性的使用。而且,要判斷何時需要強制轉換,還要區分與對象引用 強制轉換相關的編譯器錯誤和運行時錯誤。

 

 記住可以傳遞多個IS-A測試的任何Java對象都可以被看作是多態的。除了Object類型的對象之外,其他所有Java對象都是多態的,這在於它們爲自己的類型以及Object類傳遞IS-A測試。

記住,訪問對象的唯一方式是通過引用變量。關於引用,要記住的幾個要點如下:

  • 引用變量只能屬於一種類型。一經聲明,類型就永遠不能再改變(儘管它引用的對象可以改變類型) 。
  • 引用是一個變量,因此它可以重新賦予其他對象(除非該引用被聲明爲final)
  • 引用變量的類型決定了可以在該變量引用的對象上調用的方法。
  • 引用變量可以引用具有與所聲明引用的類型相同的任何對象,或者——最重要的一點是——它可以引用鎖聲明類型的任何子類型!
  • 引用變量可以聲明爲類類型或接口類型。入股甌江變量聲明爲接口類型,它就可以應用事項該接口的任何類的任何對象。

 早先我們創建了被另外兩個類PlayPiece和TilePiece擴展的GameShape,類現在假設你希望是某些形狀在遊戲板實現動畫效果,但是並非所有形狀都是可以運動的,那麼可以利用類繼承做什麼呢?

是否可以創建一個帶有animate()方法的類,並且只有某些GameShape子類是繼承自該類的?

如果可以這樣做,那麼就能夠具有PlayerPiece,它同時擴展了GameShape類和Animatable類,但是TilePiece將只會擴展GameShape。不過,這樣做是不行的!Java值支持單一的繼承!這意味着一個類只能有唯一的直接超類。換句話說,如果PlayPice是一個類,則不能這樣編寫代碼:

 那麼,存在別的方法嗎?你已經知道了答案了——創建一個Animatable接口,並且只讓那些可以實現動畫效果的GameShape紫了實現該接口。該接口的代碼如下:

 以下是實現該接口的修改過的PlayerPiece類:

因此,現在我們就有了以個PlayerPiece,它同時爲GameShape類和Aniamtable接口傳遞IS-A測試。這意味着在任何給定的時間都可以將PlayPiece視作4中事物之一,具體取決於應用變量的聲明類型:

  • Object(因爲任何對象都繼承自Object) 。
  • GameShape(因爲PlayerPiece擴展) 
  • PlayerPiece(因爲這是它的本來身份) 。
  • Animatable(因爲PlayerPiece實現Animatable) 。

以下全部都是合法的聲明,請仔細觀察:

 

這裏只有一個對象——PlayerPiece類型的一個實例——因爲有4種不同類型引用變量,它們全部都引用堆上的一個對象。一個流行的測驗時上述變量中哪一個變量可以調用displayShape()方法?提示:上述4個聲明中只有兩個可用於調用displayShape()方法。

記住,編譯器允許的方法調用只基於引用聲明的類型,而不考慮對象的類型。因此,再次考慮4中引用類型——Object、GameShape、PlayerPiece和Animatable——這4中類型中有哪些知道displayShape()方法?

1. 對編譯器來說,PlayerPiece IS-A GameShape,因此,編譯器會認爲:我看到聲明類型是PlayerPiece,並且由於PlayerPiece擴展了GameShape,這意味着PlayerPiece繼承了displayShape()方法,因此,PlayerPiece可用於調用displayShape()方法。

2. 還有,當使用聲明爲Animatable類型的引用PlayerPiece對象是,可以調用哪些方法呢?只能調用animate()方法。

3. 來自任何繼承樹的任何類也可以實現Animatable,因此,這意味着如果你具有一個方法,它帶有聲明爲Animatable類型的變元。也就是說,你可以傳入PlayerPiece對象、SpinningLogo對象以及實現Animatable的類的其他任何實例。

 

 

關於重寫

我們還未介紹一個重要的部分:及時只有編譯器知道生命的引用類型,JVM在運行時也會知道對象實際上是什麼。這意味着即使使用GameShape引用變量底啊用PlayerPiece對象的displayShape()方法,如果PlayerPiece重寫了displayShape()方法,JVM也會調用PlayerPiece的版本!JVM會在引用的另一端看到實際的對象,“看見” 它已經重寫了聲明的引用變量的方法,並且調用對象的實際類的方法。但是,要牢記另外一點:

 多態方法調用僅適用與實例方法。總是可以利用更一般的引用變量類型(超類或接口)引用一個對象,但是在運行時,基於實際對象(而不是引用類型)動態選擇的唯一事物是實例方法,而不是靜態方法,也不是變量。只有基於實際對象的類型動態地調用重寫的實例方法。

 很難理解這段話吧!我現在還不是很理解,往後看看可能會對他有進一步的瞭解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章