首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多態綜合實戰:繼承、重寫與訪問權限深度解析

     編輯:Java 相關知識

Java 多態、向上/向下轉型、protected 與 private 訪問控制,單獨看都不難,但一旦結合在一起,往往令開發者困惑不已。本文通過一個經典案例,層層剖析七大「困惑點」,帶你徹底搞懂多態運行機制與編譯期綁定規則。

案例代碼結構

兩個類:父類 A、子類 B extends A。關鍵點:

  • 雙方均有 protected int protectedab 字段
  • A 定義 private void privateTest()、protected void protectedTest(Object)、protected void protectedTest(String)
  • B 重寫 protectedTest(Object)
  • main 方法在 A 中,包含 7 個測試點

七大困惑逐一破解

困惑 1:A a2 = b1; 發生了什麼?

經典向上轉型。a2 是類型 A 的引用,指向 B 類型對象。Java 規則:父類引用可指向子類實例。

困惑 2:為什麼 b1 = a1; 編譯報錯?

b1 是 B 引用,a1 是 A 實例(非 B 或其子類)。向下轉型需顯式強轉:b1 = (B) a1;,且運行時需確保對象真為 B 類型。

困惑 3:b1.privateTest(); 編譯失敗?

private 方法僅限定義類內部訪問。子類 B 不可見,即使對象實際是 B 實例。私有方法不參與多態。

困惑 4:b1.protectedTest(helloObj); 輸出 B 的方法?

helloObj 編譯類型為 Object。JVM 採用動態綁定:運行時根據對象真實類型(B)分派方法,而非引用類型。故調用 B.protectedTest(Object)。

困惑 5:b1.protectedTest(helloStr); 編譯報 ambiguous 錯誤?

helloStr 編譯類型 String。兩條路徑均可行:

  1. String → Object,調用 B.protectedTest(Object)
  2. 直接調用 A.protectedTest(String)(繼承而來)

編譯器無法判定優先級,拋出 reference ambiguous。隱式歧義更危險(如參數順序互換導致運行時行為不符預期)。

困惑 6:a2.protectedTest(helloObj); 輸出 B 的方法?

a2 編譯類型 A,實際指向 B 對象。動態綁定生效,運行時分派至 B 實現。

困惑 7:a2.protectedTest(helloStr); 為什麼輸出 A 的方法且不報錯?

關鍵在於方法表差異:

  • a2=b1 賦值後,存在兩個句柄,指向同一數據內存,但方法表不同:a2 用 A 的方法表,b1 用 B 的
  • a2 方法表含 protectedTest(String),精確匹配,無歧義 → 編譯通過,靜態綁定至 A 版本
  • b1 方法表無 String 版本,只有 Object 版本,引發歧義 → 編譯報錯

JVM 規範:對象引用指向句柄,句柄含方法表指針與類對象指針。向上轉型不改變對象,但改變方法表視圖。

核心心法

  • 編譯看引用類型,運行看對象類型(動態綁定)
  • private 方法靜態綁定,不參與多態
  • 重載解析發生在編譯期,歧義即報錯
  • 向上轉型改變方法表視圖,子類新增重載不影響父類視圖
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved