在java的繼承體系中,一個子類對象在內(nèi)存中創(chuàng)建時(shí),實(shí)際上是包含其所有父類部分的組合體。為了確保子類對象能夠被正確地初始化,其所有父類的構(gòu)造器都必須被執(zhí)行。java文檔中“構(gòu)造器不被繼承”的說法,并非指父類構(gòu)造器不會被執(zhí)行,而是指子類不能像繼承普通方法那樣,直接擁有父類構(gòu)造器的簽名并進(jìn)行重寫。子類只能通過特定的語法(super()關(guān)鍵字)來調(diào)用父類的構(gòu)造器,而不能聲明一個與父類構(gòu)造器同名的新構(gòu)造器來“繼承”它。
當(dāng)一個子類構(gòu)造器沒有明確地調(diào)用super()(用于調(diào)用父類構(gòu)造器)或this()(用于調(diào)用當(dāng)前類的其他構(gòu)造器)時(shí),Java編譯器會自動在子類構(gòu)造器的第一行插入一個對父類無參構(gòu)造器的調(diào)用:super();。這個隱式插入的super();會確保在子類自身的初始化邏輯開始之前,其直接父類的無參構(gòu)造器已經(jīng)被執(zhí)行。這個過程會沿著繼承鏈一直向上追溯,直到Object類的構(gòu)造器被調(diào)用。
讓我們通過一個示例來理解這個機(jī)制:
示例代碼 1:隱式調(diào)用
// 父類 A public class A { public A() { System.out.println("A 的無參構(gòu)造器被調(diào)用"); } } // 子類 B public class B extends A { public B() { // 編譯器在此處隱式插入 super(); System.out.println("B 的無參構(gòu)造器被調(diào)用"); } } // 主方法 public class ConstructorCallDemo { public static void main(String[] args) { B b1 = new B(); } }
輸出:
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
A 的無參構(gòu)造器被調(diào)用 B 的無參構(gòu)造器被調(diào)用
解析:
這個過程清晰地展示了即使沒有顯式 super(),父類構(gòu)造器依然會被調(diào)用的原因。
雖然編譯器會自動處理無參父類構(gòu)造器的調(diào)用,但在某些情況下,我們需要或必須顯式地調(diào)用父類構(gòu)造器。
如果父類沒有定義任何無參構(gòu)造器,但定義了至少一個帶參數(shù)的構(gòu)造器,那么子類構(gòu)造器 必須 顯式地調(diào)用父類的某個帶參構(gòu)造器。否則,編譯器將報(bào)錯,因?yàn)樗鼰o法找到一個無參的 super() 來隱式插入。
即構(gòu)數(shù)智人是由即構(gòu)科技推出的AI虛擬數(shù)字人視頻創(chuàng)作平臺,支持?jǐn)?shù)字人形象定制、短視頻創(chuàng)作、數(shù)字人直播等。
示例代碼 2:父類無無參構(gòu)造器
// 父類 A,只包含帶參構(gòu)造器 public class A { public A(String message) { System.out.println("A 的帶參構(gòu)造器被調(diào)用: " + message); } // 注意:這里沒有定義無參構(gòu)造器 } // 子類 B public class B extends A { // public B() { // 編譯錯誤:無法找到父類 A 的無參構(gòu)造器 // System.out.println("B 的無參構(gòu)造器被調(diào)用"); // } public B(String msg) { super(msg); // 必須顯式調(diào)用父類的帶參構(gòu)造器 System.out.println("B 的帶參構(gòu)造器被調(diào)用: " + msg); } } // 主方法 public class ConstructorCallDemo { public static void main(String[] args) { // B b1 = new B(); // 如果 B 存在無參構(gòu)造器,此處會編譯錯誤 B b2 = new B("Hello from B"); } }
輸出:
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
A 的帶參構(gòu)造器被調(diào)用: Hello from B B 的帶參構(gòu)造器被調(diào)用: Hello from B
解析: 由于 A 類沒有無參構(gòu)造器,B 類的構(gòu)造器就不能依賴編譯器的隱式 super();。因此,B 類的構(gòu)造器必須顯式地通過 super(msg); 來調(diào)用 A 類的帶參構(gòu)造器,并傳遞相應(yīng)的參數(shù)。
即使父類提供了無參構(gòu)造器,子類也可以選擇顯式調(diào)用父類的帶參構(gòu)造器,以傳遞特定的初始化參數(shù)。
示例代碼 3:顯式選擇帶參構(gòu)造器
// 父類 A,包含無參和帶參構(gòu)造器 public class A { public A() { System.out.println("A 的無參構(gòu)造器被調(diào)用"); } public A(String message) { System.out.println("A 的帶參構(gòu)造器被調(diào)用: " + message); } } // 子類 B public class B extends A { public B() { // 編譯器隱式插入 super();,調(diào)用 A 的無參構(gòu)造器 System.out.println("B 的無參構(gòu)造器被調(diào)用"); } public B(String msg) { super(msg); // 顯式調(diào)用 A 的帶參構(gòu)造器 System.out.println("B 的帶參構(gòu)造器被調(diào)用: " + msg); } } // 主方法 public class ConstructorCallDemo { public static void main(String[] args) { System.out.println("--- 創(chuàng)建 B 的無參實(shí)例 ---"); B b1 = new B(); System.out.println("\n--- 創(chuàng)建 B 的帶參實(shí)例 ---"); B b2 = new B("Custom Message"); } }
輸出:
立即學(xué)習(xí)“Java免費(fèi)學(xué)習(xí)筆記(深入)”;
--- 創(chuàng)建 B 的無參實(shí)例 --- A 的無參構(gòu)造器被調(diào)用 B 的無參構(gòu)造器被調(diào)用 --- 創(chuàng)建 B 的帶參實(shí)例 --- A 的帶參構(gòu)造器被調(diào)用: Custom Message B 的帶參構(gòu)造器被調(diào)用: Custom Message
解析:b1 的創(chuàng)建演示了隱式調(diào)用,而 b2 的創(chuàng)建則展示了如何通過 super(msg) 顯式地選擇并調(diào)用父類的特定帶參構(gòu)造器。
理解Java構(gòu)造器的這一調(diào)用機(jī)制對于編寫健壯、可維護(hù)的面向?qū)ο蟠a至關(guān)重要。它確保了對象初始化的順序性和完整性,是Java繼承模型的核心組成部分。
以上就是深入理解Java構(gòu)造器:子類實(shí)例化中的父類構(gòu)造器調(diào)用機(jī)制的詳細(xì)內(nèi)容,更多請關(guān)注php中文網(wǎng)其它相關(guān)文章!
每個人都需要一臺速度更快、更穩(wěn)定的 PC。隨著時(shí)間的推移,垃圾文件、舊注冊表數(shù)據(jù)和不必要的后臺進(jìn)程會占用資源并降低性能。幸運(yùn)的是,許多工具可以讓 Windows 保持平穩(wěn)運(yùn)行。
微信掃碼
關(guān)注PHP中文網(wǎng)服務(wù)號
QQ掃碼
加入技術(shù)交流群
Copyright 2014-2025 http://ipnx.cn/ All Rights Reserved | php.cn | 湘ICP備2023035733號