一篇文章超詳細(xì)的介紹Java繼承
前言
繼承是面向?qū)ο笳Z(yǔ)法的三大特征之一。繼承可以降低代碼編寫的冗余度,提高編程的效率。通過(guò)繼承,子類獲得了父類的成員變量和方法。一個(gè)子類如何繼承父類的字段和方法,如何修改從父類繼承過(guò)來(lái)的子類的方法呢。今天我們開始學(xué)習(xí)有關(guān)Java繼承的知識(shí)。
繼承
繼承就是子類繼承父類的特征和行為,使得子類對(duì)象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
繼承的作用:通過(guò)繼承可以快速創(chuàng)建新的類,實(shí)現(xiàn)代碼的重用,提高程序的可維護(hù)性,節(jié)省大量創(chuàng)建新類的時(shí)間,提高開發(fā)效率和開發(fā)質(zhì)量。
在 Java 中通過(guò) extends 關(guān)鍵字可以申明一個(gè)類是從另外一個(gè)類繼承而來(lái)的,一般形式如下:
class 父類{
... //成員變量、成員方法
}
class 子類 extends 父類{
... //類體
}
例如:
class teacher{ //聲明一個(gè)teacher類為父類 String name; //定義父類的成員變量name、age int age; void show(){ //定義父類成員方法,將成員變量輸出 System.out.println(name); System.out.println(age); } } class Student extends teacher { //聲明一個(gè)Student類為子類并繼承父類 } public class myfirst { public static void main(String[] args) { System.out.println("學(xué)生"); Student student=new Student(); //聲明一個(gè)Student類的實(shí)例對(duì)象student student.name="Tom"; //子類調(diào)用父類的成員變量name并賦值 student.age=19; //子類調(diào)用父類的成員變量age并賦值 student.show(); //子類調(diào)用父類的成員方法show } }
運(yùn)行結(jié)果為:
學(xué)生
Tom
19
注意:
- 子類不能選擇性繼承父類;
- Java不支持多重繼承,但一個(gè)類可以實(shí)現(xiàn)多個(gè)接口,從而克服單繼承的缺點(diǎn);
- 構(gòu)造方法不會(huì)被子類繼承,但可以從子類中調(diào)用父類的構(gòu)造方法。
繼承的優(yōu)點(diǎn)
- 繼承過(guò)來(lái)的字段和方法,可以像任何其他字段和方法一樣被直接使用;
- 在子類中可以聲明一個(gè)與父類中同名的新字段或靜態(tài)方法,從而“隱藏”父類中的字段或方法;
- 可以在子類中聲明一個(gè)在父類中沒有的新字段和方法;
- 可以在子類中編寫一個(gè)父類當(dāng)中具有相同名的新實(shí)例方法,這稱為“方法重寫”或“方法覆蓋”;
- 可以在子類中編寫一個(gè)調(diào)用父類構(gòu)造方法的子類構(gòu)造方法,既可以隱式地實(shí)現(xiàn),也可以通過(guò)使用關(guān)鍵字super來(lái)實(shí)現(xiàn)。
重寫和隱藏父類方法
子類繼承了父類中的所有成員及方法,但在某種情況下,子類中該方法所表示的行為與其父類中該方法所表示的行為不完全相同,例如,在父類語(yǔ)言中定義了說(shuō)話這個(gè)方法,而在子類中說(shuō)話的方法是不同的:外國(guó)人說(shuō)英文,中國(guó)人說(shuō)中文,這時(shí)我們就需要重寫或隱藏父類的該方法。
重寫父類中的方法
當(dāng)一個(gè)子類中一個(gè)實(shí)例方法具有與其父類中的一個(gè)實(shí)例方法相同的簽名(指名稱、參數(shù)個(gè)數(shù)和類型)和返回值時(shí),稱子類中的方法“重寫”了父類的方法。例如:
class A{ public void sayHello() { //輸出英文歡迎 System.out.println("Hello,Welcome to Java!!!"); } public void sayBye() { System.out.println("GoodBye,everyone"); } } class B extends A { public void sayHello() { //輸出中文歡迎 System.out.println("大家好,歡迎學(xué)習(xí)Java?。?!"); } } public class myfirst { public static void main(String[] args) { B b=new B(); //創(chuàng)建子類B的一個(gè)實(shí)例對(duì)象,使用默認(rèn)構(gòu)造方法 b.sayHello(); //調(diào)用子類中重寫的方法 b.sayBye(); //調(diào)用父類中的方法 } }
運(yùn)行結(jié)果為:
大家好,歡迎學(xué)習(xí)Java?。?!
GoodBye,everyone
注意:重寫的方法具有與其所重寫的方法相同的名稱、參數(shù)數(shù)量、類型和返回值。
隱藏父類中的方法
如果一個(gè)子類定義了一個(gè)靜態(tài)類方法,而這個(gè)類方法與其父類的一個(gè)類方法具有相同的簽名(指名稱、參數(shù)格式和類型)和返回值,則稱在子類中的這個(gè)類方法“隱藏”了父類中的該類方法。
- 當(dāng)調(diào)用被重寫的方法時(shí),調(diào)用的版本是子類的方法;
- 當(dāng)調(diào)用被隱藏的方法時(shí),調(diào)用的版本取決于是從父類中調(diào)用還是從子類中調(diào)用。
class A{ public static void sayHello() { //靜態(tài)類方法 System.out.println("大家好,這是A的靜態(tài)類方法"); } public void sayHello2() { //實(shí)例方法 System.out.println("大家好,這是A中的實(shí)例方法"); } } class B extends A { public static void sayHello() { //靜態(tài)類方法 System.out.println("大家好,這是B的靜態(tài)類方法"); } public void sayHello2() { //實(shí)例方法 System.out.println("大家好,這是B的實(shí)例方法"); } } public class myfirst { public static void main(String[] args) { B b=new B(); //創(chuàng)建B類的實(shí)例對(duì)象b A a=b; //隱式對(duì)象類型轉(zhuǎn)換 A.sayHello(); //調(diào)用A類的靜態(tài)類方法 a.sayHello(); //調(diào)用a對(duì)象的靜態(tài)類方法 B.sayHello(); //調(diào)用B類的靜態(tài)方法 a.sayHello2(); //調(diào)用a對(duì)象的實(shí)例方法 b.sayHello2(); //調(diào)用b對(duì)象的的實(shí)例方法 A a2=new A(); //創(chuàng)建A類的實(shí)例對(duì)象a2 a2.sayHello2(); //調(diào)用a2對(duì)象的實(shí)現(xiàn)方法 } }
運(yùn)行結(jié)果為:
大家好,這是A的靜態(tài)類方法
大家好,這是A的靜態(tài)類方法
大家好,這是B的靜態(tài)類方法
大家好,這是B的實(shí)例方法
大家好,這是B的實(shí)例方法
大家好,這是A中的實(shí)例方法
可以看出,得到調(diào)用的隱藏方法是父類中的方法,而得到調(diào)用的重寫方法是子類中的方法。
方法重寫和隱藏后的修飾符
在子類中被重寫的方法,其訪問(wèn)權(quán)限允許大于但不允許小于被其重寫的方法,例如:父類中一個(gè)受保護(hù)的實(shí)例方法(protected)在子類中可以是公共的(public)的,但不可以是私有的(private)。如果一個(gè)方法在父類中是static方法,那么在子類也必須是static方法;如果一個(gè)方法在父類中是實(shí)例方法,那么在子類中也必須是實(shí)例方法。
子類訪問(wèn)父類私有成員
子類繼承其父類的所有public和protected成員,但不能繼承其父類的private成員。那么如何在子類中訪問(wèn)到父類中的字段呢,我們可以在父類中提供用來(lái)訪問(wèn)其私有字段的public或protected方法,子類使用這些方法來(lái)訪問(wèn)相應(yīng)的字段。例如:
class A{ //父類A private int value=10; //聲明一個(gè)私有變量value并賦值為10 public int getvalue() { //聲明一個(gè)公有成員方法getvalue,返回value return value; } } class B extends A{ //A的子類B } public class myfirst { public static void main(String[] args) { B b=new B(); //創(chuàng)建子類B的一個(gè)實(shí)例對(duì)象 System.out.println("子類通過(guò)父類提供的公共接口訪問(wèn)A中的私有字段value:"+b.getvalue()); } }
運(yùn)行結(jié)果為:
子類通過(guò)父類提供的公共接口訪問(wèn)A中的私有字段value:10
使用super關(guān)鍵字
使用super調(diào)用父類中重寫的方法、訪問(wèn)父類中被隱藏的字段
子類重寫了父類中的某一個(gè)方法,隱藏父類中的字段,假如想在子類中訪問(wèn)到父類中被重寫的方法和隱藏父類的字段,可以在子類中通過(guò)使用關(guān)鍵字super來(lái)調(diào)用父類中被重寫的方法和訪問(wèn)父類中被隱藏的字段。例如:
package first; class A{ public String name="張飛"; //添加成員變量 public void say() { //添加成員方法say System.out.println("我是父類A成員方法say"); } } class B extends A{ public String name="關(guān)羽"; //與父類中同名的字段,隱藏父類 public void say(){ //重寫方法say super.say(); //使用super關(guān)鍵字調(diào)用父類中的方法 System.out.println("我是子類B成員方法say"); System.out.println("父類的name名字:"+super.name); //使用super關(guān)鍵字訪問(wèn)父類中的變量 } } public class myfirst { public static void main(String[] args) { B b=new B(); //創(chuàng)建子類的一個(gè)實(shí)例對(duì)象 b.say(); //調(diào)用子類中重寫的方法 System.out.println("子類的name名字:"+b.name); //調(diào)用子類中的name } }
運(yùn)行結(jié)果為:
我是父類A成員方法say
我是子類B成員方法say
父類的name名字:張飛
子類的name名字:關(guān)羽
使用super調(diào)用父類的無(wú)參數(shù)構(gòu)造方法/有參數(shù)構(gòu)造方法
子類不繼承其父類的構(gòu)造方法。
- 當(dāng)使用無(wú)參數(shù)的super()時(shí),父類的無(wú)參數(shù)構(gòu)造方法就會(huì)被調(diào)用;
- 當(dāng)使用帶有參數(shù)的super()方法時(shí),父類的有參數(shù)構(gòu)造方法就會(huì)被調(diào)用。
例如:
class SuperClass { //創(chuàng)建父類SuperClass private int n; //聲明一個(gè)私有變量n SuperClass(){ //父類無(wú)參數(shù)構(gòu)造方法 System.out.println("這是父類SuperClass無(wú)參數(shù)構(gòu)造方法"); } SuperClass(int n) { //父類有參數(shù)構(gòu)造方法 System.out.println("這是父類SuperClass有參數(shù)構(gòu)造方法"); this.n = n; } } class SubClass extends SuperClass{ // SubClass類繼承SuperClass類 private int n; //聲明一個(gè)私有變量n SubClass(){ // 自動(dòng)調(diào)用父類的無(wú)參數(shù)構(gòu)造器 System.out.println("這是子類無(wú)參數(shù)構(gòu)造方法"); } public SubClass(int n){ //子類有參數(shù)構(gòu)造方法 super(300); //調(diào)用父類中帶有參數(shù)的構(gòu)造器 System.out.println("這是子類有參數(shù)構(gòu)造方法"+n); this.n = n; } } public class myfirst { public static void main(String[] args) { SubClass sc1 = new SubClass(); //創(chuàng)建子類SubClass實(shí)例對(duì)象,調(diào)用其無(wú)參數(shù)構(gòu)造方法 SubClass sc2 = new SubClass(100); //創(chuàng)建子類SubClass實(shí)例對(duì)象,調(diào)用其有參數(shù)構(gòu)造方法 } }
運(yùn)行結(jié)果為:
這是父類SuperClass無(wú)參數(shù)構(gòu)造方法
這是子類無(wú)參數(shù)構(gòu)造方法
這是父類SuperClass有參數(shù)構(gòu)造方法
這是子類有參數(shù)構(gòu)造方法100
注意
- 如果要初始化父類中的字段,可以在子類的構(gòu)造方法中通過(guò)關(guān)鍵字super調(diào)用父類的構(gòu)造方法;
- 對(duì)父類的構(gòu)造放的調(diào)用必須放在子類構(gòu)造方法的第一行;
- 如果父類構(gòu)造器沒有參數(shù),則在子類的構(gòu)造器中不需要使用 super 關(guān)鍵字調(diào)用父類構(gòu)造器,系統(tǒng)會(huì)自動(dòng)調(diào)用父類的無(wú)參構(gòu)造器;
- 如果父類的構(gòu)造器帶有參數(shù),則必須在子類的構(gòu)造器中顯式地通過(guò) super 關(guān)鍵字調(diào)用父類的構(gòu)造器并配以適當(dāng)?shù)膮?shù)列表;
- 子類是不繼承父類的構(gòu)造器(構(gòu)造方法或者構(gòu)造函數(shù))的,它只是調(diào)用(隱式或顯式)。
附:繼承的使用和認(rèn)識(shí)
1、繼承是怎么實(shí)現(xiàn)的?
使用extends 和 implements 關(guān)鍵字
extends 繼承的都是對(duì)象
implements 繼承實(shí)現(xiàn)并實(shí)現(xiàn)的是接口
2、在繼承的場(chǎng)景下,同一樣?xùn)|西,怎么區(qū)分是你老爹的還是你自己的?
使用super 與 this 關(guān)鍵字
super關(guān)鍵字:我們可以通過(guò)super關(guān)鍵字來(lái)實(shí)現(xiàn)對(duì)父類成員的訪問(wèn),用來(lái)引用當(dāng)前對(duì)象的父類。
this關(guān)鍵字:指向自己的引用。
3、父類的某些方法不想被子類繼承,怎么處理?
對(duì)方法或?qū)傩赃M(jìn)行 private 關(guān)鍵字或final關(guān)鍵字修飾
private 關(guān)鍵字修飾,子類無(wú)法使用和繼承
final關(guān)鍵字修飾,無(wú)法繼承,但是否可以被使用需要看權(quán)限屬性
總結(jié)
到此這篇關(guān)于Java繼承的文章就介紹到這了,更多相關(guān)Java繼承介紹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用Apache POI庫(kù)讀取Excel表格文檔的示例
POI庫(kù)是Apache提供的用于在Windows下讀寫各類微軟Office文檔的Java庫(kù),這里我們就來(lái)看一下Java使用Apache POI庫(kù)讀取Excel表格文檔的示例:2016-06-06淺談一下maven優(yōu)缺點(diǎn)及使用和特點(diǎn)
這篇文章主要介紹了淺談一下maven優(yōu)缺點(diǎn)及使用和特點(diǎn),一個(gè)項(xiàng)目管理工具軟件,那么maven項(xiàng)目有什么優(yōu)缺點(diǎn)呢,讓我們一起來(lái)看看吧2023-03-03JPA添加Pageable實(shí)現(xiàn)翻頁(yè)時(shí)報(bào)錯(cuò)的問(wèn)題
這篇文章主要介紹了解決JPA添加Pageable實(shí)現(xiàn)翻頁(yè)時(shí)報(bào)錯(cuò)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java使用POI實(shí)現(xiàn)excel文件的導(dǎo)入和導(dǎo)出
這篇文章主要為大家詳細(xì)介紹了Java如何使用POI實(shí)現(xiàn)excel文件的導(dǎo)入和導(dǎo)出功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12詳談Enumeration接口和Iterator接口的區(qū)別
下面小編就為大家?guī)?lái)一篇詳談Enumeration接口和Iterator接口的區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-08-08Java程序員編程性能優(yōu)化必備的34個(gè)小技巧(總結(jié))
這篇文章主要介紹了Java程序員編程性能優(yōu)化必備的34個(gè)小技巧(總結(jié)),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-07-07java開發(fā)Dubbo負(fù)載均衡與集群容錯(cuò)示例詳解
這篇文章主要為大家介紹了java開發(fā)Dubbo負(fù)載均衡與集群容錯(cuò)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步2021-11-11java自帶的MessageDigest實(shí)現(xiàn)文本的md5加密算法
這篇文章主要介紹了java自帶的MessageDigest實(shí)現(xiàn)文本的md5加密算法,需要的朋友可以參考下2015-12-12