一道簡單的題目
看到這個標題時可能很多朋友會嗤之以鼻,難不成簡單的訪問修飾符還有什么新花樣嗎沛膳?別急扔枫,麻煩您先看一下這個簡單的題目。
這無非就是一個簡單運行時多態(tài)問題锹安,眾所周知短荐,Java的多態(tài)分為編譯時多態(tài)和運行時多態(tài)兩種。其中叹哭, 編譯時多態(tài)主要指方法的重載忍宋,運行時多態(tài)指程序中定義的對象引用所指向的具體類型在運行期間才確定。 運行時多態(tài)有三個條件:
繼承
方法重寫(覆蓋)
向上轉型
main函數中风罩,base指向的實際上是Impl對象糠排,因此在調用sayHi()方法時,會執(zhí)行Impl對象的sayHi()方法而非Base對象的sayHi()方法超升,因此入宦,輸出的內容顯然是Impl:Hi。
實際上是這樣的嗎室琢?然而很不幸乾闰,輸出的卻是 Base:Hi。問題出在哪兒研乒?難道這不滿足運行時多態(tài)的條件汹忠?不應該啊淋硝,首先雹熬,Impl類繼承了Base類,其次谣膳,Impl類重寫了Base類的sayHi()方法竿报,最后,調用時進行了向上轉型继谚。三個貌似條件都滿足烈菌,但是等等,回憶一下方法重寫的要求:
子類方法的訪問權限必須大于等于父類方法;
-
子類方法的返回類型必須是父類方法返回類型或為父類方法返回類型的子類型芽世。
貌似也滿足啊挚赊,我們再看一下JLS中對方法重寫的規(guī)定:
翻譯過來大概為:
A是C的超類
C沒有繼承mA
mC是mA的簽名的子簽名
-
下面的多個條件之一要滿足:
mA是public的
mA是protected的 mA在C所處的包中具有包訪問權限,且mC覆蓋了來自C的某個超類中的mA
...訪問修飾符
看來我們忽略了方法的訪問修飾符的問題济瓢。Java中訪問修飾符規(guī)定及其訪問范圍如下表所示:
訪問權限 當前類 同包 子類 其他包 public √ √ √ √ protected √ √ √ × default √ √ × × private √ × × × 那么荠割,當子類位于當前類內部、同一包下旺矾、其他包下時訪問權限會發(fā)生什么變化呢蔑鹦?是否還遵循表格中的規(guī)定呢?對于這個問題箕宙,我們只需要記住最大訪問權限原則即可嚎朽,所謂最大訪問權限原則即子類的在不同位置時訪問權限修飾符表現(xiàn)的實際權限以最大的那個為準。依據該原則柬帕,子類在不同位置時對父類中的方法及變量的訪問權限如下表所示:
子類中訪問權限 當前類 同包 其他包 public √ √ √ protected √ √ √ default √ √ × private √ × × 回到題目中盼产,由于子類Impl與父類Base位于同一包下催享,而Base中的sayHi()方法的修飾符為private,對子類不可見,因此不滿足方法重寫的要求叫倍,因此調用的仍然是Base中的方法,而非子類中的方法醋粟。
這個細節(jié)看起來很不起眼蹋偏,但實際上卻包含了訪問修飾符的權限及方法重寫、多態(tài)等細節(jié)饶火,算得上是一道好題鹏控。