吃透Java基礎十四:繼承引發的“血案”

在Java中,只允許單繼承,也就是說一個類只能繼承一個父類,但是可以實現多個接口。本文我們討論一下子類和父類的構造方法調用順序、代碼塊執行順序、方法的重寫與重載。

一、構造方法調用順序

1、何為構造方法

構造方法是類的一種特殊方法,用來初始化類的一個新的對象,每個類至少有一個構造方法,如果類中沒有顯式定義構造方法,編譯器在編譯的時候會生成一個默認的構造方法,默認的構造方法不包含任何參數,並且方法體為空。如果類中顯式地定義了一個或多個構造方法,則 Java 不再提供默認構造方法。

構造方法必須具有和類名相同的名稱,而且沒有返回類型。構造方法的默認返回類型就是對象類型本身,並且構造方法不能被 static、final、synchronized、abstract 和 native 修飾。

在一個類中,與類名相同的方法就是構造方法。每個類可以具有多個構造方法,但要求它們各自包含不同的方法參數。

構造方法可以用public、protected、默認、private修飾。

2、子類構造方法調用父類構造方法

子類構造方法要麼調用父類無參構造方法(包括當父類沒有構造方法時。系統默認給的無參構造方法),要麼調用父類有參構造方法。當子類構造方法調用父類無參構造方法,一般都是默認不寫的,要寫的話就是super(),且要放在構造方法的第一句。當子類構造方法要調用父類有參數的構造方法,那麼子類的構造方法中必須要用super(參數)調用父類構造方法,且要放在構造方法的第一句。

看完如下例子對子類父類構造函數調用順序應該就能明白了:


吃透Java基礎十四:繼承引發的“血案”


運行輸出:


吃透Java基礎十四:繼承引發的“血案”


二、代碼塊執行順序

Java中代碼塊分為普通代碼塊和靜態代碼塊,普通代碼塊是屬於實例對象的,其實在編譯期編譯器會把普通代碼塊的內容放在構造函數里面來執行的。靜態代碼塊是屬於類的,是隨著類的初始化而調用的,那麼類是什麼時候初始化呢?請參考之前寫的[吃透Java基礎三:觸發類初始化的五種方式](https://blog.csdn.net/u013277209/article/details/102699028)

1、普通代碼塊編譯後自動添加到構造函數最上面執行

看下面例子:


吃透Java基礎十四:繼承引發的“血案”


編譯後的class文件反編譯:


吃透Java基礎十四:繼承引發的“血案”


2、有繼承關係的靜態代碼塊和普通代碼塊調用順序

只需要記住一點:**靜態代碼塊是在類初始化的時候調用的,普通代碼塊是在創建對象實例的時候在構造函數里面調用的,類初始化一定在創建對象實例之前,所以靜態代碼塊一定在普通代碼塊之前調用。**

看如下例子:


吃透Java基礎十四:繼承引發的“血案”


運行輸出:


吃透Java基礎十四:繼承引發的“血案”


三、方法的重載與重寫

方法的重寫(Overriding)和重載(Overloading)是java多態性的不同表現,重寫是父類與子類之間多態性的一種表現,重載可以理解成多態的具體表現形式。

1、重載

重載(overloading) 是在一個類裡面,方法名字相同,而參數不同。返回類型可以相同也可以不同。每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。最常用的地方就是構造器的重載。

規則:

  • 被重載的方法必須改變參數列表(參數個數或類型不一樣)。
  • 被重載的方法可以改變返回類型。
  • 被重載的方法可以改變訪問修飾符。
  • 被重載的方法可以聲明新的或更廣的檢查異常。
  • 方法能夠在同一個類中或者在一個子類中被重載。
  • 無法以返回值類型作為重載函數的區分標準。

綜上:參數列表區分重載


吃透Java基礎十四:繼承引發的“血案”


2、重寫

重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫, 方法名和形參都不能改變。子類重寫父類方法的規則:

  • 子類重寫的方法的方法名和形參列表與父類被重寫的方法的方法名和形參列表相同。
  • 子類重寫的方法的權限修飾符不小於父類被重寫的方法的權限修飾符,特殊情況:子類不能重寫父類被聲明為private權限的方法。
  • 返回值類型:
  1. 父類是void,子類只能是void。
  2. 父類是A類型,子類是A類或A類的子類。
  3. 父類是基本數據類型(如:int),子類返回值類型必須相同。
  • 子類重寫的方法拋出的異常的類型不大於父類被重寫的方法拋出的異常類型。

如下例子:


吃透Java基礎十四:繼承引發的“血案”


吃透Java基礎十四:繼承引發的“血案”


分享到:


相關文章: