Java編程關于子類重寫父類方法問題的理解
子類重新實現(xiàn)父類的方法稱重寫;重寫時可以修改訪問權限修飾符和返回值,方法名和參數(shù)類型及個數(shù)都不可以修改;僅當返回值為類類型時,重寫的方法才可以修改返回值類型,且必須是父類方法返回值的子類;要么就不修改,與父類返回值類型相同。那么,該如何理解呢?為什么要是父類返回值類型的子類?
提出問題:子類必須重寫父類所有方法嗎?
Java,子類不是必須重寫父類所有方法的,分為以下兩種情況:
父類方法為抽象方法時,子類必須重寫(實現(xiàn))所有父類的抽象方法;
父類方法為普通方法時,子類可以重寫父類方法,也可以不重寫。
舉例如下:
abstract class A{
public void a(){
}
public abstract void b();
}
public class B extends A{
//必須重寫b方法,a方法可以不重寫
public void b(){
}
}
還是先看示例,詳見下文。
包human中定義了三個類,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);
}
輸出結果為:
li li
有沒有人跟我一樣,第一反應輸出應該為“l(fā)i liu”呢,怎么兩個都是“l(fā)i”?
仔細分析一下,看下面的幾張內存圖就明白了。
第1、第2條語句分別創(chuàng)建一個子類對象和一個父類對象,其中,stu指向子類對象,per指向父類對象。如下面圖1所示:
接著執(zhí)行第3條語句:per = stu.overRide();;
stu先調用overRide(),方法體里創(chuàng)建了一個子類對象,并讓臨時變量stu指向該對象,其存儲位置就是以C為首地址的內存塊;
然后把該對象的變量name賦值為“l(fā)i”;最后返回stu的值并賦給per,也就是說,雖然per是父類對象引用,但最后指向了overRide()里創(chuàng)建的子類對象,這里以藍色箭頭表示; 原先指向的以B為首地址的父類對象這時沒有引用指向它,這里把紅色箭頭變?yōu)樘摼€表示。此時訪問per的name,顯然是“l(fā)i”。內存結構見圖2:
再接著要執(zhí)行per = per.overRide();,調用overRide()方法;
由于子類重寫了父類的overRide()方法,雖然per為父類對象引用,此時父類的該方法被覆蓋,所以此時要調用子類的方法;執(zhí)行過程同上,per不再指向以C為首地址的子類對象,改為指向新創(chuàng)建的子類對象,以D為首地址,如圖3所示。
同上面一樣的道理,此時訪問per的name仍然為“l(fā)i”,因為父類的overRide()兩次壓根都沒有被調用到。
修改一下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);
//
}
此時定義了一個父類對象引用per2,并讓它與per指向同一個對象;最后兩行,由per2調用overRide()方法,很顯然要調用父類的方法,所以方法體中創(chuàng)建的也是父類的對象,再把結果返回給per2,此時per2指向新創(chuàng)建的父類對象,該父類對象的name就為“l(fā)iu”了。
說了這么多,貌似還沒解決開頭的問題,為什么是父類返回值類型的子類?為方便說明,記父類的返回值類型為A。
我的理解是,這是為了向上轉型;既然子類重寫了父類的方法,有時候就需要用父類對象引用來調用子類重寫的方法,在上面例子的情況下,也就是說要把A的子類對象引用賦給A的對象引用,如果此時返回值類型不是A類或A的子類,其他類的對象引用是不能賦給A的對象引用的,這樣就會出錯;所以說,子類重寫的方法,如果返回值為類類型,其返回值類型必須與父類返回值類型相同或為父類返回值類型的子類。
不知道有沒有說清楚。
PS:例子選得不是特別好,如果返回值類型是與Person和Student不相干的類,可能更好理解,不然容易把返回值的類與方法所屬的類混淆。
總結
以上就是本文關于Java編程關于子類重寫父類方法問題的理解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站:
Java中的靜態(tài)內部類詳解及代碼示例
Java源碼解析之object類
Java AtomicInteger類的使用方法詳解
如有不足之處,歡迎留言指出。
您可能感興趣的文章
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10Java Socket編程(三) 服務器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java經驗點滴:處理沒有被捕獲的異常
- 01-10Java Socket編程(四) 重復和并發(fā)服務器
- 01-10Java中的浮點數(shù)分析
- 01-10面向對象編程:Java中的抽象數(shù)據類型


閱讀排行
本欄相關
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10JVM的垃圾回收機制詳解和調優(yōu)
- 01-10Java Socket編程(三) 服務器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10J2SE 1.5版本的新特性一覽
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java Socket編程(四) 重復和并發(fā)服務
- 01-10Java經驗點滴:處理沒有被捕獲的異常
隨機閱讀
- 01-11ajax實現(xiàn)頁面的局部加載
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設置
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10delphi制作wav文件的方法
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10C#中split用法實例總結


