Java繼承與多態(tài)的正確打開方式
一.概述
面向?qū)ο蟪绦蛟O(shè)計(jì)的三大原則是封裝性,繼承性和多態(tài)性。繼承性是子類自動(dòng)共享父類的數(shù)據(jù)和方法的機(jī)制,它是由類的派生功能體現(xiàn)的。繼承具有傳遞性,使得一個(gè)類可以繼承另一個(gè)類的屬性和方法,這樣通過抽象出共同的屬性和方法組件新的類,便于代碼的重用。而多態(tài)是指不同類型的對(duì)象接收相同的消息時(shí)產(chǎn)生不同的行為,這里的消息主要是對(duì)類成員函數(shù)的調(diào)用,而不同的行為是指類成員函數(shù)的不同實(shí)現(xiàn)。當(dāng)對(duì)象接收到發(fā)送給它的消息時(shí),根據(jù)該對(duì)象所屬的類,動(dòng)態(tài)選用在該類中定義的實(shí)現(xiàn)算法。
二.繼承
2.1 繼承的概述
在現(xiàn)實(shí)中存在很多如圖所示的關(guān)系:
出租車,卡車和公交車都是汽車的一種,分別擁有相似的特征。例如,引擎的數(shù)量,外觀顏色等。它們擁有相似的行為,如剎車和加速的功能。但是每種不同的交通工具又有自己的特征,如公交車擁有和其他交通工具不同的特性和行為——最大載客數(shù)量和到指定站點(diǎn)要報(bào)站的特點(diǎn),而卡車的主要功能是送貨物,也就是載貨和卸貨,因此擁有最大載重量的特性。
在面向?qū)ο蟮某绦蛟O(shè)計(jì)中該怎樣描述現(xiàn)實(shí)世界的這種狀況呢?這就用到繼承的概念。
所謂繼承,就是從已有的類中派生出新的類,新的類能吸收已有類的數(shù)據(jù)屬性和行為,并能擴(kuò)展新的能力。已有的類一般稱為父類(基類或超類),這個(gè)過程也稱為類的派生。由基類產(chǎn)生的新類稱為派生類或子類,派生類同樣可以作為基類再派生新的子類,這樣就形成了類間的層次結(jié)構(gòu)。
基類和派生類類的關(guān)系如下:
- 基類是派生類的抽象(基類抽象了派生類的公共特征)。
- 派生類是對(duì)基類的擴(kuò)展。
- 派生類和基類的關(guān)相當(dāng)于“是一個(gè)(is a)”的關(guān)系,即派生類是基類的一個(gè)對(duì)象,而不是“有(has)”的關(guān)系,即類的對(duì)象包含一個(gè)或多個(gè)其他類的對(duì)象作為該類的屬性。
2.2 繼承機(jī)制
定義教師類,其中一類教師為Net教師,屬性為姓名,所屬部門,方法為授課,自我介紹。
public class NetTeacher { private String name; private String school; public NetTeacher(String myName,String mySchool){ name = myName; school = mySchool; } public void giveLession(){ System.out.println("啟動(dòng) VS2021 "); System.out.println("知識(shí)點(diǎn)講解"); System.out.println("總結(jié)提問"); } public void introduction(){ System.out.println("大家好!我是" + schoool + "的" + name + " 。"); } }
定義教師類,其中一類教師為Java教師,屬性為姓名,所屬部門,方法為授課,自我介紹。
public class JavaTeacher { private String name; private String school; public JavaTeacher(String myName,String mySchool){ name = myName; school = mySchool; } public void giveLession(){ System.out.println("啟動(dòng) IDEA2021 "); System.out.println("知識(shí)點(diǎn)講解"); System.out.println("總結(jié)提問"); } public void introduction(){ System.out.println("大家好!我是" + schoool + "的" + name + " 。"); } }
在程序處理中,發(fā)現(xiàn)兩個(gè)類的定義非常相似,有很多相同點(diǎn),如教師的屬性姓名,所屬部門類似,類的方法也基本相同。
針對(duì)這種情況,將Java教師類和Net教師類的共性抽取出來,形成父類Teacher類,使得Net教師和Java教師成為Teacher類的子類,則子類繼承父類的基本屬性和方法,就簡(jiǎn)化了子類的定義。上述代碼可以修改如下:
public class Teacher { private String name; private String school; public Teacher(String myName,String mySchool){ name = myName; school = mySchool; } public void giveLession(){ System.out.println("知識(shí)點(diǎn)講解"); System.out.println("總結(jié)提問"); } public void introduction(){ System.out.println("大家好!我是" + schoool + "的" + name + " 。"); } } 子類JavaTeacher: public class JavaTeacher extends Teacher { public JavaTeacher(String myName,String mySchool){ super(myName,mySchool); } public void giveLession(){ System.out.println("啟動(dòng) IDEA2021 "); super.giveLession; } 子類NetTeacher: public class NetTeacher extends Teacher { public NetTeacher(String myName,String mySchool){ super(myName,mySchool); } public void giveLession(){ System.out.println("啟動(dòng) VS2021 "); super.giveLession; }
子類自動(dòng)繼承父類的屬性和方法,子類中不再存在重復(fù)代碼,從而實(shí)現(xiàn)代碼的重用。
通過關(guān)鍵字 extends,分別創(chuàng)建父類 Teacher 的子類 JavaTeacher 和 NetTecher 。子類繼承父類所有的成員變量和成員方法,但不能繼承父類的構(gòu)造方法。在子類的構(gòu)造方法中,可使用語句super (參數(shù)列表)調(diào)用父類的構(gòu)造方法,如子類構(gòu)造方法中的語句 super(myName,mySchool)。
extends 說明要構(gòu)建一個(gè)新類,該類從已存在的類派生而來。派生的定義過程,實(shí)際是經(jīng)歷了以下幾個(gè)過程:
- 子類繼承父類中被聲明為 public 和 protected 的成員變量和成員方法,但是不能繼承被聲明為 private 的成員變量和成員方法。
- 重寫父類成員,包括數(shù)據(jù)成員和成員函數(shù)。如果子類聲明了一個(gè)與父類成員函數(shù)相同的成員函數(shù),子類中的新成員則屏蔽了父類同名成員,類似函數(shù)中的局部變量屏蔽了全局變量,稱為同名覆蓋(Overriding)。
- 定義新成員。新成員是派生類自己的新特性。派生類新成員的加入使得派生類在功能上有所發(fā)展。
- 必須在派類中重寫構(gòu)造方法,因?yàn)闃?gòu)造方法不能繼承。
2.3 類中屬性,方法的繼承與覆蓋
1.屬性的繼承與覆蓋
子類可以繼承父類的所有非私有屬性。
子類也可以覆蓋繼承的成員變量,對(duì)于子類可以從父類繼承的成員變量,只要子類中定義的成員變量和父類中的成員變量同名,子類就覆蓋了繼承的成員變量。
當(dāng)子類執(zhí)行它自己定義的方法時(shí),所操作的就是它自己定義的數(shù)據(jù)成員,,從而覆蓋父類繼承來的數(shù)據(jù)成員。
2.方法的繼承與覆蓋
父類中非私有( private )方法可以被子類所繼承。
在子類繼承父類的成員方法時(shí),應(yīng)注意一下兩項(xiàng):
- 子類不能訪問父類的 private 成員方法,但子類可以訪問父類的 piblic ,protected 成員方法。
- 訪問 protected 時(shí),子類和同一包內(nèi)的方法都能訪問父類的 protected 成員方法,但其他方法不能訪問。
方法的覆蓋是指子類中定義一個(gè)方法,并且這個(gè)方法的名字,返回類型,參數(shù)列表與父類繼承的方法完全相同。
2.4 super 關(guān)鍵字
子類不能繼承父類的構(gòu)造方法。
如果基類中沒有默認(rèn)構(gòu)造方法或希望調(diào)用帶參數(shù)的基類構(gòu)造方法,要使用關(guān)鍵字 super 來顯示調(diào)用基類構(gòu)造方法。使用關(guān)鍵字 super 調(diào)用基類構(gòu)造方法的語句,必須是子類構(gòu)造方法的第一個(gè)可執(zhí)行語句。調(diào)用基類構(gòu)造方法時(shí),傳遞的參數(shù)不能是關(guān)鍵字 this 或當(dāng)前對(duì)象的非靜態(tài)成員。
super 關(guān)鍵字主要應(yīng)用于繼承關(guān)系實(shí)現(xiàn)子類對(duì)父類方法的調(diào)用,包括對(duì)父類構(gòu)造方法和一般方法的調(diào)用。具體使用方法如下:
(1)子類的構(gòu)造方法如果要引用 super ,必須把 super 放在構(gòu)造方法的第一個(gè)可執(zhí)行語句。例如:
public CommonEmployee (String name,double bonus){ super (name); //通過 super () 的調(diào)用,給父類的數(shù)據(jù)成員賦初值 this.bonus = bonus; // this 指當(dāng)前對(duì)象 System.out.println("子類構(gòu)造方法的調(diào)用"); }
(2)在 Java 中,有時(shí)還會(huì)遇到子類中的成員變量或方法與父類中的成員變量或方法同名。同名子類中的成員變量或方法名優(yōu)先級(jí)高,所以子類中的同名成員變量或方法覆蓋了父類的成員變量或方法,但是我們?nèi)绻胍褂酶割愔械倪@個(gè)成員變量或方法,就需要用到 super .
(3)可以用 super 直接傳遞參數(shù)。見下面代碼:
public class Person { Person(){ prt("A Person."); } Person(String name){ prt("A person name is:" + name); } public static void prt(String s){ System.out.println(s); } } public class Chinese extends Person { Chinese(){ super(); //調(diào)用父類無形參構(gòu)造方法 prt("A chinese"); //調(diào)用父類的方法prt } Chinese(String name){ super(name); //調(diào)用父類具有相同形參的構(gòu)造方法 prt("his name is:" + name); } Chinese(String name,int age){ this(name); //調(diào)用當(dāng)前具有相同形參的構(gòu)造方法 prt("his age is:" + age); } public static void main(String[] args) { Chinese cn = new Chinese(); cn = new Chinese("Kevin"); cn = new Chinese("Jhone",21); } }
程序分析如下:
- main()中首先構(gòu)建Chinese的第一個(gè)對(duì)象cn, 語句cn = new Chinese()調(diào)用子類無參的構(gòu)造方法Chinese(),在構(gòu)造方法中super()語句調(diào)用父類的無參構(gòu)造方法Person(),在父類無參的構(gòu)造方法中調(diào)用父類的方法prt(),程序輸出結(jié)果A Person,接下來返回子類的構(gòu)造方法的調(diào)用處,繼續(xù)執(zhí)行下面的語句pr("A chinese."),則調(diào)用父類的方法prt輸出結(jié)果A chinese.結(jié)束第一條語句。
- 程序繼續(xù)執(zhí)行第二條語句cn = new Chinese("kevin");此時(shí)調(diào)用子類具有一 個(gè)參數(shù)參的構(gòu)造方法Chinese(name),在構(gòu)造方法中super(name)語句調(diào)用父類的有參構(gòu)造方法prt("A person name is:"+ name),程序輸出結(jié)果A person name is:kevin,接下來返回子類的構(gòu)造方法的調(diào)用處,繼續(xù)執(zhí)行下面的語句prt("his name is:"+ name),則調(diào)用父類的方法prt輸出結(jié)果his name is:kevin,結(jié)束第二條語句。
- 接下來程序繼續(xù)執(zhí)行第三條語句cn = new Chinese("Jhone,"22);程序執(zhí)行時(shí)先調(diào)用子類具有兩個(gè)參數(shù)參的構(gòu)造方法Chinese(name, age), 在構(gòu)造方法中this ( name )語句則調(diào)用的是當(dāng)前具有相同參數(shù)的構(gòu)造方法,即調(diào)用子類具有一個(gè)參數(shù)參的構(gòu)造方法Chinese(name),接下來調(diào)用父類的有參構(gòu)造方法Person(name),為父類的name進(jìn)行初始化,再接下來在父類有參的構(gòu)造方法中調(diào)用父類的方法prt("A person name is:"+ name),程序輸出結(jié)果A person name is: Jhone,接下來返回子類的構(gòu)造方法的調(diào)用處,繼續(xù)執(zhí)行下面的語句prt("his name is:"+ name),則調(diào)用父類的方法prt輸出結(jié)果his name is: Jhone,調(diào)用結(jié)束后程序返回子類構(gòu)造方法Chinese(name,age)執(zhí)行語句prt("his age is:"+ age); 輸出結(jié)果his age is:22,結(jié)束第二條語句。
三. 多態(tài)
多態(tài)是指在父類中定義的屬性和方法被子類繼承之后,可以具有不同的數(shù)據(jù)類型或表現(xiàn)出不同的行為,這使得同一個(gè)屬性或方法在父類及其各個(gè)子類中具有不同的含義。
對(duì)面向?qū)ο髞碚f,多態(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)。其中編譯時(shí)多態(tài)是靜態(tài)的,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來區(qū)分不同的方法。通過編譯之后會(huì)變成兩個(gè)不同的方法,在運(yùn)行時(shí)談不上多態(tài)。而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的,它是通過動(dòng)態(tài)綁定來實(shí)現(xiàn)的,也就是大家通常所說的多態(tài)性。
Java 實(shí)現(xiàn)多態(tài)有 3 個(gè)必要條件:繼承、重寫和向上轉(zhuǎn)型。只有滿足這 3 個(gè)條件,開發(fā)人員才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn)代碼處理不同的對(duì)象,從而執(zhí)行不同的行為。
- 繼承:在多態(tài)中必須存在有繼承關(guān)系的子類和父類。
- 重寫:子類對(duì)父類中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類的方法。
- 向上轉(zhuǎn)型:在多態(tài)中需要將子類的引用賦給父類對(duì)象,只有這樣該引用才既能可以調(diào)用父類的方法,又能調(diào)用子類的方法。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
maven配置阿里云倉庫的實(shí)現(xiàn)方法(2022年)
本文主要介紹了maven配置阿里云倉庫的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03spring結(jié)合redis如何實(shí)現(xiàn)數(shù)據(jù)的緩存
這篇文章主要介紹了spring結(jié)合redis如何實(shí)現(xiàn)數(shù)據(jù)的緩存,實(shí)現(xiàn)的目的目的不是加快查詢的速度,而是減少數(shù)據(jù)庫的負(fù)擔(dān),需要的朋友可以參考下2015-12-12淺談HBase在SpringBoot項(xiàng)目里的應(yīng)用(含HBaseUtil工具類)
這篇文章主要介紹了淺談HBase在SpringBoot項(xiàng)目里的應(yīng)用(含HBaseUtil工具類),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10SpringBoot集成RabbitMQ的方法(死信隊(duì)列)
這篇文章主要介紹了SpringBoot集成RabbitMQ的方法(死信隊(duì)列),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Java AbstractMethodError案例分析詳解
這篇文章主要介紹了Java AbstractMethodError案例分析詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08SpringBoot?實(shí)現(xiàn)自定義的?@ConditionalOnXXX?注解示例詳解
這篇文章主要介紹了SpringBoot?實(shí)現(xiàn)自定義的?@ConditionalOnXXX?注解,通過示例代碼介紹了實(shí)現(xiàn)一個(gè)自定義的?@Conditional?派生注解,Conditional?派生注解的類如何注入到?spring?容器,需要的朋友可以參考下2022-08-08