Java基礎:一、伴隨多態的可互換對象(7)

  • 2020 年 3 月 17 日
  • 筆記

泛化

在處理類型的層次結構時,經常把一個對象不當作它所屬的特定類型來對象,而是將其當作其基類的對象類對象。這稱為「泛化」 ,這樣可以編寫出不依賴特定類型的程式碼。

後期綁定

這將會產生一個問題,當我們將導出類型的對象當作其泛化基類型來看待時,比如我們自行車看作是交通工具,那麼仍然存在一個問題,編譯器在編譯時是不可能知道自己應該執行哪一段程式碼將被執行,那對象如何會根據自身的具體類型來執行恰當的程式碼?

舉個例子,在下面的圖中,BirdController對象僅僅處理泛化的Bird對象,而不了解它們的確切類型。從BirdController的角度看,這麼做非常方便,因為不需要編寫特別的程式碼來判定要處理的Bird對象的確切類型或其行為。當move()方法被調用時,即便忽略Bird的具體類型,也會產生正確的行為(Goose(鵝)會走、非或游泳,Penguin(企鵝)走或游泳),這是如何發生的呢?

為了解決這個問題,面向對象程式設計語言使用了後期綁定的概念。當向對象發送消息時,被調用的程式碼直到運行時才能確定。編譯器確保被調用方法的存在,並對調用參數和返回值執行類型檢查,但是並不知道將被執行的確切程式碼。

為了執行後期綁定,Java使用一小段特殊的程式碼替代絕對地址調用。這段程式碼使用在對象存儲的資訊來計算方法體的地址。這樣,根據這一小段程式碼的內容,每個對象都可以具有不同的行為表現,當向一個對象發送消息時,該對象就能夠直到對這條消息應該做些什麼。在Java 中,動態綁定是默認行為,不需要添加額外的關鍵字來實現多態(C++是使用virthal關鍵字來聲明某個方法以實現後期綁定屬性所帶來的靈活性)。

向上轉型

// 編寫一個方法,這個方法可以將任何Shape類型作為參數  void doSomthing(Shape shape){    shape.erase();    //...    shape.draw();  }
Circle circle = new Circle();  Triangle triangle = new Triangle();  Line line = new Line();  doSomthing(circle);  doSomthing(triangle);  doSomthing(line);

對doSomthing()的調用會自動地正確處理,而不管對象的確切類型,比如doSomthing(circle); 由於Circle可以被doSomething()看作是Shape,也就是說,doSomthing()可以發送給Shape的任何消息,Circle也可以接收。

因為發送基類的任何消息,導出類都可以接收,那麼將導出類看作是它的基類的過程稱為向上轉型。