A、重寫規則之一:
重寫方法不能比被重寫方法限制有更嚴格的訪問級別。 (但是可以更廣泛,比如父類方法是包訪問權限,子類的重寫方法是public訪問權限。)
比如:Object類有個toString()方法,開始重寫這個方法的,時候我們總容易忘記public修飾符,編譯器當然不會放過任何教訓我們 的機會。出錯的原因就是:沒有加任何訪問修飾符的方法具有包訪問權限,包訪問權限比public當然要嚴格了,所以編譯器會報錯的。
B、重寫規則之二:
參數列表必須與被重寫方法的相同。 重寫有個孿生的弟弟叫重載,也就是后面要出場的。如果子類方法的參數與父類對應的方法不同,那么就是你認錯人了,那是重載,不是重寫。
C、重寫規則之三:
返回類型必須與被重寫方法的返回類型相同。
父類方法A:void eat(){} 子類方法B:int eat(){} 兩者雖然參數相同,可是返回類型不同,所以不是重寫。 父類方法A:int eat(){} 子類方法B:long eat(){} 返回類型雖然兼容父類,但是不同就是不同,所以不是重寫。
D、重寫規則之四:
重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者不拋出異常。
1 import java.io.*; 2 3 public class Test { 4 public static void main (String[] args){ 5 Animal h = new Horse(); 6 try { 7 h.eat(); 8 } catch (Exception e) { 9 10 } 11 } 12 } 13 14 class Animal { 15 public void eat() 16 throws Exception{ 17 System.out.println ("Animal is eating."); 18 throw new Exception(); 19 } 20 } 21 22 class Horse extends Animal{ 23 public void eat() 24 25 throws IOException{ 26 System.out.println ("Horse is eating."); 27 throw new IOException(); 28 } 29 }
這個例子中,父類拋出了檢查異常Exception,子類拋出的IOException是Exception的子類,也即是比被重寫的方法拋出了 更有限的異常,這是可以的。如果反過來,父類拋出IOException,子類拋出更為寬泛的Exception,那么不會通過編譯的。
注意:這種限制只是針對檢查異常,至於運行時異常RuntimeException及其子類不再這個限制之中。
E、重寫規則之五:
不能重寫被標識為final的方法。
F、重寫規則之六:
如果一個方法不能被繼承,則不能重寫它。 比較典型的就是父類的private方法。
下例會產生一個有趣的現象。
1 public class Test { 2 public static void main (String[] args) { 3 //Animal h = new Horse(); 4 Horse h = new Horse(); 5 h.eat(); 6 } 7 } 8 9 class Animal { 10 private void eat(){ 11 System.out.println ("Animal is eating."); 12 } 13 } 14 15 class Horse extends Animal{ 16 public void eat(){ 17 System.out.println ("Horse is eating."); 18 } 19 }
這段代碼是能通過編譯的。表面上看來違反了第六條規則,但實際上那是一點巧合。Animal類的eat()方法不能被繼承,因此Horse類中的 eat()方法是一個全新的方法,不是重寫也不是重載,只是一個只屬於Horse類的全新的方法!這點讓很多人迷惑了,但是也不是那么難以理解。
main()方法如果是這樣: Animal h = new Horse(); //Horse h = new Horse(); h.eat(); 編譯器會報錯,為什么呢?Horse類的eat()方法是public的啊!應該可以調用啊!
這里就牽扯到一個向上轉型的概念了,當父類引用了子類的一個實例時,子類復寫了父類的方法會覆蓋父類中相同的方法,但子類中有而父類中沒有的方法父類就無法調用。在這個例子中,由於Animal中的eat方法是private的,所以子類中的eat方法不算復寫了父類的eat方法,這是一個新方法,所以調用父類的eat方法時,就無法調用子類的eat方法,而父類的eat方法為private,所以發生了錯誤。
請牢記,多態只看父類引用的方法,而不看子類對象的方法。