繼承是 Java 面向?qū)ο缶幊痰暮诵奶匦灾唬试S一個(gè)類(子類)繼承另一個(gè)類(父類)的屬性和方法,從而實(shí)現(xiàn)代碼復(fù)用、簡(jiǎn)化開發(fā)并建立類之間的層次關(guān)系。在繼承關(guān)系中,構(gòu)造方法的調(diào)用邏輯與普通方法不同,需要遵循特定規(guī)則。掌握繼承的實(shí)現(xiàn)方式和構(gòu)造方法的調(diào)用機(jī)制,是理解類層級(jí)設(shè)計(jì)的基礎(chǔ)。
一、Java 繼承的實(shí)現(xiàn)方式
(一)繼承的基本語法
Java 通過extends關(guān)鍵字實(shí)現(xiàn)繼承,語法格式為:
修飾符 class 子類名 extends 父類名 {...}
其中,子類(派生類)會(huì)自動(dòng)獲得父類(基類)中非私有的成員變量和方法,同時(shí)可以定義自己的獨(dú)有屬性和方法,實(shí)現(xiàn)功能擴(kuò)展。
示例:定義父類Person和子類Student
// 父類:描述人的共性class Person { String name; int age; void eat() { System.out.println(name + "正在吃飯"); }}// 子類:繼承Person,增加學(xué)生特有的屬性和方法class Student extends Person { String studentId; // 獨(dú)有屬性:學(xué)號(hào) // 獨(dú)有方法:學(xué)習(xí) void study() { System.out.println(name + "(學(xué)號(hào):" + studentId + ")正在學(xué)習(xí)"); }}
子類Student繼承了Person的name、age變量和eat()方法,同時(shí)新增了studentId變量和study()方法,實(shí)現(xiàn)了 “學(xué)生是特殊的人” 這一邏輯關(guān)系。
(二)繼承的特性
單繼承限制:Java 中一個(gè)子類只能直接繼承一個(gè)父類(單繼承),避免多繼承導(dǎo)致的邏輯混亂,但可通過多層繼承實(shí)現(xiàn)功能傳遞(如Student extends Person,Graduate extends Student)。
訪問權(quán)限控制:父類的private成員(變量或方法)對(duì)子類不可見,public和protected成員可被繼承,默認(rèn)修飾符(同包可見)在同包子類中可訪問。
方法重寫(Override):子類可重寫父類的方法,修改其實(shí)現(xiàn)邏輯,需保證方法名、參數(shù)列表和返回值類型與父類一致。
示例:重寫Person類的eat()方法
class Student extends Person { // 重寫父類方法 @Override void eat() { System.out.println(name + "在學(xué)校食堂吃飯"); }}
二、繼承中構(gòu)造方法的調(diào)用規(guī)則
構(gòu)造方法用于對(duì)象初始化,在繼承關(guān)系中,子類構(gòu)造方法的調(diào)用會(huì)觸發(fā)父類構(gòu)造方法的執(zhí)行,遵循 “先初始化父類,再初始化子類” 的原則。
(一)默認(rèn)調(diào)用父類無參構(gòu)造方法
若子類構(gòu)造方法中未顯式調(diào)用父類構(gòu)造方法,Java 會(huì)自動(dòng)隱式調(diào)用父類的無參構(gòu)造方法,確保父類成員先初始化。
示例:隱式調(diào)用父類構(gòu)造方法
class Person { // 父類無參構(gòu)造方法 Person() { System.out.println("Person無參構(gòu)造方法被調(diào)用"); }}class Student extends Person { // 子類構(gòu)造方法 Student() { // 隱式調(diào)用super(),即父類無參構(gòu)造方法 System.out.println("Student無參構(gòu)造方法被調(diào)用"); }}// 測(cè)試public class Test { public static void main(String[] args) { Student stu = new Student(); // 輸出順序: // Person無參構(gòu)造方法被調(diào)用 // Student無參構(gòu)造方法被調(diào)用 }}
(二)顯式調(diào)用父類構(gòu)造方法(super())
若父類沒有無參構(gòu)造方法(如僅定義了有參構(gòu)造),子類必須在構(gòu)造方法的第一行通過super(參數(shù))顯式調(diào)用父類的有參構(gòu)造方法,否則編譯報(bào)錯(cuò)。
示例:顯式調(diào)用父類有參構(gòu)造
class Person { String name; // 父類僅定義有參構(gòu)造,無默認(rèn)無參構(gòu)造 Person(String name) { this.name = name; System.out.println("Person有參構(gòu)造方法被調(diào)用,姓名:" + name); }}class Student extends Person { String studentId; // 子類構(gòu)造方法必須顯式調(diào)用父類有參構(gòu)造 Student(String name, String id) { super(name); // 第一行調(diào)用父類構(gòu)造,傳遞name參數(shù) this.studentId = id; System.out.println("Student有參構(gòu)造方法被調(diào)用,學(xué)號(hào):" + id); }}// 測(cè)試public class Test { public static void main(String[] args) { Student stu = new Student("張三", "2023001"); // 輸出順序: // Person有參構(gòu)造方法被調(diào)用,姓名:張三 // Student有參構(gòu)造方法被調(diào)用,學(xué)號(hào):2023001 }}
(三)構(gòu)造方法調(diào)用的注意事項(xiàng)
super()必須放在子類構(gòu)造方法的第一行,否則無法通過編譯,這是為了保證父類初始化先于子類。
若父類既無無參構(gòu)造也無有參構(gòu)造(僅默認(rèn)構(gòu)造),子類可隱式調(diào)用;若父類自定義了構(gòu)造方法,默認(rèn)無參構(gòu)造會(huì)失效,需顯式定義或在子類中顯式調(diào)用有參構(gòu)造。
子類構(gòu)造方法中不能同時(shí)調(diào)用super()和this()(子類其他構(gòu)造方法),兩者均需放在第一行,存在沖突。
三、繼承的典型應(yīng)用場(chǎng)景
代碼復(fù)用:將多個(gè)類的共性屬性和方法提取到父類,減少重復(fù)代碼。例如,Student和Teacher都繼承Person類,共享name、age等屬性。
功能擴(kuò)展:子類在繼承父類的基礎(chǔ)上新增特性,如VIPUser繼承User類,增加discount(折扣)屬性和getVipService()方法。
多態(tài)實(shí)現(xiàn):基于繼承的方法重寫是多態(tài)的基礎(chǔ),如父類引用指向子類對(duì)象(Person p = new Student()),調(diào)用方法時(shí)會(huì)執(zhí)行子類重寫的實(shí)現(xiàn)。
四、繼承使用的注意事項(xiàng)
避免過度繼承:多層繼承可能導(dǎo)致類層級(jí)復(fù)雜,難以維護(hù),建議繼承層級(jí)不超過 3 層。
符合邏輯關(guān)系:繼承應(yīng)遵循 “is-a” 原則(子類是父類的一種),如Cat extends Animal(貓是動(dòng)物)合理,Book extends Person(書是人)則不符合邏輯。
謹(jǐn)慎使用protected:父類protected成員可被子類訪問,若過度使用可能破壞封裝性,建議通過getter/setter方法控制訪問。
Java 繼承通過extends關(guān)鍵字實(shí)現(xiàn)類的層級(jí)關(guān)系,核心價(jià)值是代碼復(fù)用與擴(kuò)展;而構(gòu)造方法的調(diào)用遵循 “父類優(yōu)先” 原則,需注意顯式與隱式調(diào)用的場(chǎng)景。掌握這些知識(shí),能幫助開發(fā)者設(shè)計(jì)更清晰、更靈活的類結(jié)構(gòu),為理解多態(tài)、抽象類等高級(jí)特性奠定基礎(chǔ)。