若想實(shí)現(xiàn)一個合格重寫方法,而不是重載,那么必須同時滿足下面的要求! A、重寫規(guī)則之一: 重寫方法不能比被重寫方法限制有更嚴(yán)格的訪問級別。 (但是可以更廣泛,比如父類方法是包訪問權(quán)限,子類的重寫方法是public訪問權(quán)限。) 比如:Object類有個toString()方法,開始重寫這個方法的時候我們總?cè)菀淄沺ublic修飾符,編譯器當(dāng)然不會放過任何教訓(xùn)我們 的機(jī)會。出錯的原因就是:沒有加任何訪問修飾符的方法具有包訪問權(quán)限,包訪問權(quán)限比public當(dāng)然要嚴(yán)格了,所以編譯器會報錯的。 B、重寫規(guī)則之二: 參數(shù)列表必須與被重寫方法的相同。 重寫有個孿生的弟弟叫重載,也就是后面要出場的。如果子類方法的參數(shù)與父類對應(yīng)的方法不同,那么就是你認(rèn)錯人了,那是重載,不是重寫。 C、重寫規(guī)則之三:
返回類型必須與被重寫方法的返回類型相同。
父類方法A:void eat(){} 子類方法B:int eat(){} 兩者雖然參數(shù)相同,可是返回類型不同,所以不是重寫。
父類方法A:int eat(){} 子類方法B:long eat(){} 返回類型雖然兼容父類,但是不同就是不同,所以不是重寫。
D、重寫規(guī)則之四:
重寫方法不能拋出新的異常或者比被重寫方法聲明的檢查異常更廣的檢查異常。但是可以拋出更少,更有限或者不拋出異常。
import java.io.*;
public class Test {
public static void main (String[] args) {
Animal h = new Horse();
try {
h.eat();
}
catch (Exception e) {
}
}
}
class Animal {
public void eat() throws Exception{
System.out.println ("Animal is eating.");
throw new Exception();
}
}
class Horse extends Animal{
public void eat() throws IOException{
System.out.println ("Horse is eating.");
throw new IOException();
}
}
這個例子中,父類拋出了檢查異常Exception,子類拋出的IOException是Exception的子類,也即是比被重寫的方法拋出了更有限的異常,這是可以的。如果反過來,父類拋出IOException,子類拋出更為寬泛的Exception,那么不會通過編譯的。
注意:這種限制只是針對檢查異常,至于運(yùn)行時異常RuntimeException及其子類不再這個限制之中。
E、重寫規(guī)則之五:
不能重寫被標(biāo)識為final的方法。
F、重寫規(guī)則之六:
如果一個方法不能被繼承,則不能重寫它。
比較典型的就是父類的private方法。下例會產(chǎn)生一個有趣的現(xiàn)象。
public class Test {
public static void main (String[] args) {
//Animal h = new Horse();
Horse h = new Horse();
h.eat();
}
}
class Animal {
private void eat(){
System.out.println ("Animal is eating.");
}
}
class Horse extends Animal{
public void eat(){
System.out.println ("Horse is eating.");
}
}
這段代碼是能通過編譯的。表面上看來違反了第六條規(guī)則,但實(shí)際上那是一點(diǎn)巧合。Animal類的eat()方法不能被繼承,因此Horse類中的 eat()方法是一個全新的方法,不是重寫也不是重載,只是一個只屬于Horse類的全新的方法!這點(diǎn)讓很多人迷惑了,但是也不是那么難以理解。
main()方法如果是這樣:
Animal h = new Horse();
//Horse h = new Horse();
h.eat();
編譯器會報錯,為什么呢?Horse類的eat()方法是public的啊!應(yīng)該可以調(diào)用啊!請牢記,多態(tài)只看父類引用的方法,而不看子類對象的方法!