子類重新實現父類的方法稱重寫;重寫時可以修改訪問許可權修飾符和返回值,方法名和參數類型及個數都不可以修改;僅當返回值為類類型時,重寫的方法才可以修改返回值類型,且必須是父類方法返回值的子類;要麼就不修改,與父類返回值類型相同。那麼,該如何理解呢?為什麼要是父類返回值類型的子類? 還是先看示例,詳見下文 ...
子類重新實現父類的方法稱重寫;重寫時可以修改訪問許可權修飾符和返回值,方法名和參數類型及個數都不可以修改;僅當返回值為類類型時,重寫的方法才可以修改返回值類型,且必須是父類方法返回值的子類;要麼就不修改,與父類返回值類型相同。那麼,該如何理解呢?為什麼要是父類返回值類型的子類?
還是先看示例,詳見下文。
包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); }
輸出結果為:
1 li 2 liView Code
有沒有人跟我一樣,第一反應輸出應該為“li liu”呢,怎麼兩個都是“li”?
仔細分析一下,看下麵的幾張記憶體圖就明白了。
第1、第2條語句分別創建一個子類對象和一個父類對象,其中,stu指向子類對象,per指向父類對象。如下麵圖1所示:
圖1
接著執行第3條語句:per = stu.overRide();;
stu先調用overRide(),方法體里創建了一個子類對象,並讓臨時變數stu指向該對象,其存儲位置就是以C為首地址的記憶體塊;
然後把該對象的變數name賦值為“li”;最後返回stu的值並賦給per,也就是說,雖然per是父類對象引用,但最後指向了overRide()里創建的子類對象,這裡以藍色箭頭表示; 原先指向的以B為首地址的父類對象這時沒有引用指向它,這裡把紅色箭頭變為虛線表示。此時訪問per的name,顯然是“li”。記憶體結構見圖2:
圖2
再接著要執行per = per.overRide();,調用overRide()方法;
由於子類重寫了父類的overRide()方法,雖然per為父類對象引用,此時父類的該方法被覆蓋,所以此時要調用子類的方法;執行過程同上,per不再指向以C為首地址的子類對象,改為指向新創建的子類對象,以D為首地址,如圖3所示。
同上面一樣的道理,此時訪問per的name仍然為“li”,因為父類的overRide()兩次壓根都沒有被調用到。
圖3
修改一下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()方法,很顯然要調用父類的方法,所以方法體中創建的也是父類的對象,再把結果返回給per2,此時per2指向新創建的父類對象,該父類對象的name就為“liu”了。
說了這麼多,貌似還沒解決開頭的問題,為什麼是父類返回值類型的子類?為方便說明,記父類的返回值類型為A。
我的理解是,這是為了向上轉型;既然子類重寫了父類的方法,有時候就需要用父類對象引用來調用子類重寫的方法,在上面例子的情況下,也就是說要把A的子類對象引用賦給A的對象引用,如果此時返回值類型不是A類或A的子類,其他類的對象引用是不能賦給A的對象引用的,這樣就會出錯;所以說,子類重寫的方法,如果返回值為類類型,其返回值類型必須與父類返回值類型相同或為父類返回值類型的子類。
不知道有沒有說清楚。
PS:例子選得不是特別好,如果返回值類型是與Person和Student不想乾的類,可能更好理解,不然容易把返回值的類與方法所屬的類混淆。