Java編程關(guān)于子類重寫父類方法問題的理解
子類重新實(shí)現(xiàn)父類的方法稱重寫;重寫時(shí)可以修改訪問權(quán)限修飾符和返回值,方法名和參數(shù)類型及個(gè)數(shù)都不可以修改;僅當(dāng)返回值為類類型時(shí),重寫的方法才可以修改返回值類型,且必須是父類方法返回值的子類;要么就不修改,與父類返回值類型相同。那么,該如何理解呢?為什么要是父類返回值類型的子類?
提出問題:子類必須重寫父類所有方法嗎?
Java,子類不是必須重寫父類所有方法的,分為以下兩種情況:
父類方法為抽象方法時(shí),子類必須重寫(實(shí)現(xiàn))所有父類的抽象方法;
父類方法為普通方法時(shí),子類可以重寫父類方法,也可以不重寫。
舉例如下:
abstract class A{ public void a(){ } public abstract void b(); } public class B extends A{ //必須重寫b方法,a方法可以不重寫 public void b(){ } }
還是先看示例,詳見下文。
包human中定義了三個(gè)類,Person類、Student類和TestMain類,其中Student類是Person類的子類。代碼分別如下:
Person類的代碼如下:
package human; public class Person { String name; int age; //test:重寫 public Person overRide() { Person per = new Person(); per.name = "liu"; return per; } }
Student類重寫了父類的overRide()方法,代碼如下:
package human; public class Student extends Person { String stuNumber; int score; //test:重寫 public Student overRide() { Student stu = new Student(); stu.name = "li"; return stu; } }
TestMain類的代碼如下:
package human; public class TestMain { public static void main(String[] args) { Student stu = new Student(); Person per = new Person(); per = stu.overRide(); System.out.println(per.name); per = per.overRide(); System.out.println(per.name); }
輸出結(jié)果為:
li li
有沒有人跟我一樣,第一反應(yīng)輸出應(yīng)該為“l(fā)i liu”呢,怎么兩個(gè)都是“l(fā)i”?
仔細(xì)分析一下,看下面的幾張內(nèi)存圖就明白了。
第1、第2條語句分別創(chuàng)建一個(gè)子類對(duì)象和一個(gè)父類對(duì)象,其中,stu指向子類對(duì)象,per指向父類對(duì)象。如下面圖1所示:
接著執(zhí)行第3條語句:per = stu.overRide();;
stu先調(diào)用overRide(),方法體里創(chuàng)建了一個(gè)子類對(duì)象,并讓臨時(shí)變量stu指向該對(duì)象,其存儲(chǔ)位置就是以C為首地址的內(nèi)存塊;
然后把該對(duì)象的變量name賦值為“l(fā)i”;最后返回stu的值并賦給per,也就是說,雖然per是父類對(duì)象引用,但最后指向了overRide()里創(chuàng)建的子類對(duì)象,這里以藍(lán)色箭頭表示; 原先指向的以B為首地址的父類對(duì)象這時(shí)沒有引用指向它,這里把紅色箭頭變?yōu)樘摼€表示。此時(shí)訪問per的name,顯然是“l(fā)i”。內(nèi)存結(jié)構(gòu)見圖2:
再接著要執(zhí)行per = per.overRide();,調(diào)用overRide()方法;
由于子類重寫了父類的overRide()方法,雖然per為父類對(duì)象引用,此時(shí)父類的該方法被覆蓋,所以此時(shí)要調(diào)用子類的方法;執(zhí)行過程同上,per不再指向以C為首地址的子類對(duì)象,改為指向新創(chuàng)建的子類對(duì)象,以D為首地址,如圖3所示。
同上面一樣的道理,此時(shí)訪問per的name仍然為“l(fā)i”,因?yàn)楦割惖膐verRide()兩次壓根都沒有被調(diào)用到。
修改一下TestMain,如下所示:
package human; public class TestMain { public static void main(String[] args) { Student stu = new Student(); Person per = new Person(); Person per2 = per; // per = stu.overRide(); System.out.println(per.name); per = per.overRide(); System.out.println(per.name); per2 = per2.overRide(); // System.out.println(per2.name); // }
此時(shí)定義了一個(gè)父類對(duì)象引用per2,并讓它與per指向同一個(gè)對(duì)象;最后兩行,由per2調(diào)用overRide()方法,很顯然要調(diào)用父類的方法,所以方法體中創(chuàng)建的也是父類的對(duì)象,再把結(jié)果返回給per2,此時(shí)per2指向新創(chuàng)建的父類對(duì)象,該父類對(duì)象的name就為“l(fā)iu”了。
說了這么多,貌似還沒解決開頭的問題,為什么是父類返回值類型的子類?為方便說明,記父類的返回值類型為A。
我的理解是,這是為了向上轉(zhuǎn)型;既然子類重寫了父類的方法,有時(shí)候就需要用父類對(duì)象引用來調(diào)用子類重寫的方法,在上面例子的情況下,也就是說要把A的子類對(duì)象引用賦給A的對(duì)象引用,如果此時(shí)返回值類型不是A類或A的子類,其他類的對(duì)象引用是不能賦給A的對(duì)象引用的,這樣就會(huì)出錯(cuò);所以說,子類重寫的方法,如果返回值為類類型,其返回值類型必須與父類返回值類型相同或?yàn)楦割惙祷刂殿愋偷淖宇悺?/p>
不知道有沒有說清楚。
PS:例子選得不是特別好,如果返回值類型是與Person和Student不相干的類,可能更好理解,不然容易把返回值的類與方法所屬的類混淆。
總結(jié)
以上就是本文關(guān)于Java編程關(guān)于子類重寫父類方法問題的理解的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
如有不足之處,歡迎留言指出。
- 詳解Java中方法重寫與重載的區(qū)別(面試高頻問點(diǎn))
- Java如何重寫object類的equals方法詳解
- Java中final修飾的方法是否可以被重寫示例詳解
- Java重寫equals及hashcode方法流程解析
- 淺談java 重寫equals方法的種種坑
- Java繼承方法重寫實(shí)現(xiàn)原理及解析
- java子類調(diào)用父類的方法中包含子類重寫的實(shí)例方法
- Java自動(dòng)添加重寫的toString方法詳解
- java中為何重寫equals時(shí)必須重寫hashCode方法詳解
- Java中方法的重寫與成員變量的隱藏
- 重寫Java中的equals方法介紹
- Java基礎(chǔ)之方法重寫詳解
相關(guān)文章
Java中OkHttp 超時(shí)設(shè)置的實(shí)現(xiàn)
超時(shí)設(shè)置是網(wǎng)絡(luò)編程中不可忽視的一部分,本文就來介紹一下Java中OkHttp 超時(shí)設(shè)置的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的示例代碼
這篇文章主要為大家介紹了如何用Java語言實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的生成,項(xiàng)目采用了springboot,maven等技術(shù),感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下2022-02-02Java ArrayList如何實(shí)現(xiàn)生成不重復(fù)隨機(jī)數(shù)
這篇文章主要介紹了Java ArrayList如何實(shí)現(xiàn)生成不重復(fù)隨機(jī)數(shù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09MyBatis使用嵌套查詢collection和association的實(shí)現(xiàn)
本文詳細(xì)介紹了使用MyBatis框架進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),如何利用collection標(biāo)簽實(shí)現(xiàn)一對(duì)多的嵌套查詢和使用association標(biāo)簽實(shí)現(xiàn)一對(duì)一的嵌套查詢,感興趣的可以了解一下2024-09-09Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解
這篇文章主要介紹了Spring中bean的初始化和銷毀幾種實(shí)現(xiàn)方式詳解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11