Java 重寫時應當遵守的 11 條規則
CSDN 的小夥伴們,大傢好,我是沉默王二。
重寫(Overriding)算是 Java 中一個非常重要的概念,理解重寫到底是什麼對每個 Java 程序員來說都至關重要,這篇文章就來給大傢說說重寫過程中應當遵守的 12 條規則。
01、什麼是重寫?
重寫帶來瞭一種非常重要的能力,可以讓子類重新實現從超類那繼承過來的方法。在下面這幅圖中,Animal 是父類,Dog 是子類,Dog 重新實現瞭 move()
方法用來和父類進行區分,畢竟狗狗跑起來還是比較有特色的。
重寫的方法和被重寫的方法,不僅方法名相同,參數也相同,隻不過,方法體有所不同。
02、哪些方法可以被重寫?
規則一:隻能重寫繼承過來的方法。
因為重寫是在子類重新實現從父類繼承過來的方法時發生的,所以隻能重寫繼承過來的方法,這很好理解。這就意味著,隻能重寫那些被 public、protected 或者 default 修飾的方法,private 修飾的方法無法被重寫。
Animal 類有 move()
、eat()
和 sleep()
三個方法:
public class Animal { public void move() { } protected void eat() { } void sleep(){ } }
Dog 類來重寫這三個方法:
public class Dog extends Animal { public void move() { } protected void eat() { } void sleep(){ } }
OK,完全沒有問題。但如果父類中的方法是 private 的,就行不通瞭。
public class Animal { private void move() { } }
此時,Dog 類中的 move()
方法就不再是一個重寫方法瞭,因為父類的 move()
方法是 private 的,對子類並不可見。
public class Dog extends Animal { public void move() { } }
03、哪些方法不能被重寫?
規則二:final、static 的方法不能被重寫。
一個方法是 final 的就意味著它無法被子類繼承到,所以就沒辦法重寫。
public class Animal { final void move() { } }
由於父類 Animal 中的 move()
是 final 的,所以子類在嘗試重寫該方法的時候就出現編譯錯誤瞭!
同樣的,如果一個方法是 static 的,也不允許重寫,因為靜態方法可用於父類以及子類的所有實例。
public class Animal { final void move() { } }
重寫的目的在於根據對象的類型不同而表現出多態,而靜態方法不需要創建對象就可以使用。沒有瞭對象,重寫所需要的“對象的類型”也就沒有存在的意義瞭。
04、重寫方法的要求
規則三:重寫的方法必須有相同的參數列表。
public class Animal { void eat(String food) { } }
Dog 類中的 eat()
方法保持瞭父類方法 eat()
的同一個調調,都有一個參數——String 類型的 food。
public class Dog extends Animal { public void eat(String food) { } }
一旦子類沒有按照這個規則來,比如說增加瞭一個參數:
public class Dog extends Animal { public void eat(String food, int amount) { } }
這就不再是重寫的范疇瞭,當然也不是重載的范疇,因為重載考慮的是同一個類。
規則四:重寫的方法必須返回相同的類型。
父類沒有返回類型:
public class Animal { void eat(String food) { } }
子類嘗試返回 String:
public class Dog extends Animal { public String eat(String food) { return null; } }
於是就編譯出錯瞭(返回類型不兼容)。
規則五:重寫的方法不能使用限制等級更嚴格的權限修飾符。
可以這樣來理解:
- 如果被重寫的方法是 default,那麼重寫的方法可以是 default、protected 或者 public。
- 如果被重寫的方法是 protected,那麼重寫的方法隻能是 protected 或者 public。
- 如果被重寫的方法是 public, 那麼重寫的方法就隻能是 public。
舉個例子,父類中的方法是 protected:
public class Animal { protected void eat() { } }
子類中的方法可以是 public:
public class Dog extends Animal { public void eat() { } }
如果子類中的方法用瞭更嚴格的權限修飾符,編譯器就報錯瞭。
規則六:重寫後的方法不能拋出比父類中更高級別的異常。
舉例來說,如果父類中的方法拋出的是 IOException,那麼子類中重寫的方法不能拋出 Exception,可以是 IOException 的子類或者不拋出任何異常。這條規則隻適用於可檢查的異常。
可檢查(checked)異常必須在源代碼中顯式地進行捕獲處理,不檢查(unchecked)異常就是所謂的運行時異常,比如說 NullPointerException、ArrayIndexOutOfBoundsException 之類的,不會在編譯器強制要求。
父類拋出 IOException:
public class Animal { protected void eat() throws IOException { } }
子類拋出 FileNotFoundException 是可以滿足重寫的規則的,因為 FileNotFoundException 是 IOException 的子類。
public class Dog extends Animal { public void eat() throws FileNotFoundException { } }
如果子類拋出瞭一個新的異常,並且是一個 checked 異常:
public class Dog extends Animal { public void eat() throws FileNotFoundException, InterruptedException { } }
那編譯器就會提示錯誤:
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()無法覆蓋com.itwanger.overriding.Animal中的eat()
被覆蓋的方法未拋出java.lang.InterruptedException
但如果子類拋出的是一個 unchecked 異常,那就沒有沖突:
public class Dog extends Animal { public void eat() throws FileNotFoundException, IllegalArgumentException { } }
如果子類拋出的是一個更高級別的異常:
public class Dog extends Animal { public void eat() throws Exception { } }
編譯器同樣會提示錯誤,因為 Exception 是 IOException 的父類。
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()無法覆蓋com.itwanger.overriding.Animal中的eat()
被覆蓋的方法未拋出java.lang.Exception
05、如何調用被重寫的方法?
規則七:可以在子類中通過 super 關鍵字來調用父類中被重寫的方法。
子類繼承父類的方法而不是重新實現是很常見的一種做法,在這種情況下,可以按照下面的形式調用父類的方法:
super.overriddenMethodName();
來看例子。
public class Animal { protected void eat() { } }
子類重寫瞭 eat()
方法,然後在子類的 eat()
方法中,可以在方法體的第一行通過 super.eat()
調用父類的方法,然後再增加屬於自己的代碼。
public class Dog extends Animal { public void eat() { super.eat(); // Dog-eat } }
06、重寫和構造方法
規則八:構造方法不能被重寫。
因為構造方法很特殊,而且子類的構造方法不能和父類的構造方法同名(類名不同),所以構造方法和重寫之間沒有任何關系。
07、重寫和抽象方法
規則九:如果一個類繼承瞭抽象類,抽象類中的抽象方法必須在子類中被重寫。
先來看這樣一個接口類:
public interface Animal { void move(); }
接口中的方法默認都是抽象方法,通過反編譯是可以看得到的:
public interface Animal { public abstract void move(); }
如果一個抽象類實現瞭 Animal 接口,move()
方法不是必須被重寫的:
public abstract class AbstractDog implements Animal { protected abstract void bark(); }
但如果一個類繼承瞭抽象類 AbstractDog,那麼 Animal 接口中的 move()
方法和抽象類 AbstractDog 中的抽象方法 bark()
都必須被重寫:
public class BullDog extends AbstractDog { public void move() {} protected void bark() {} }
08、重寫和 synchronized 方法
規則十:synchronized 關鍵字對重寫規則沒有任何影響。
synchronized 關鍵字用於在多線程環境中獲取和釋放監聽對象,因此它對重寫規則沒有任何影響,這就意味著 synchronized 方法可以去重寫一個非同步方法。
09、重寫和 strictfp 方法
規則十一:strictfp 關鍵字對重寫規則沒有任何影響。
如果你想讓浮點運算更加精確,而且不會因為硬件平臺的不同導致執行的結果不一致的話,可以在方法上添加 strictfp 關鍵字。因此 strictfp 關鍵和重寫規則無關。
到此這篇關於Java 重寫時應當遵守的 11 條規則的文章就介紹到這瞭,更多相關Java 重寫規則內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- None Found