Java 重寫時(shí)應(yīng)當(dāng)遵守的 11 條規(guī)則
CSDN 的小伙伴們,大家好,我是沉默王二。
重寫(Overriding)算是 Java 中一個(gè)非常重要的概念,理解重寫到底是什么對(duì)每個(gè) Java 程序員來說都至關(guān)重要,這篇文章就來給大家說說重寫過程中應(yīng)當(dāng)遵守的 12 條規(guī)則。
01、什么是重寫?
重寫帶來了一種非常重要的能力,可以讓子類重新實(shí)現(xiàn)從超類那繼承過來的方法。在下面這幅圖中,Animal 是父類,Dog 是子類,Dog 重新實(shí)現(xiàn)了 move() 方法用來和父類進(jìn)行區(qū)分,畢竟狗狗跑起來還是比較有特色的。

重寫的方法和被重寫的方法,不僅方法名相同,參數(shù)也相同,只不過,方法體有所不同。
02、哪些方法可以被重寫?
規(guī)則一:只能重寫繼承過來的方法。
因?yàn)橹貙懯窃谧宇愔匦聦?shí)現(xiàn)從父類繼承過來的方法時(shí)發(fā)生的,所以只能重寫繼承過來的方法,這很好理解。這就意味著,只能重寫那些被 public、protected 或者 default 修飾的方法,private 修飾的方法無(wú)法被重寫。
Animal 類有 move()、eat() 和 sleep() 三個(gè)方法:
public class Animal {
public void move() { }
protected void eat() { }
void sleep(){ }
}
Dog 類來重寫這三個(gè)方法:
public class Dog extends Animal {
public void move() { }
protected void eat() { }
void sleep(){ }
}
OK,完全沒有問題。但如果父類中的方法是 private 的,就行不通了。
public class Animal {
private void move() { }
}
此時(shí),Dog 類中的 move() 方法就不再是一個(gè)重寫方法了,因?yàn)楦割惖?move() 方法是 private 的,對(duì)子類并不可見。
public class Dog extends Animal {
public void move() { }
}
03、哪些方法不能被重寫?
規(guī)則二:final、static 的方法不能被重寫。
一個(gè)方法是 final 的就意味著它無(wú)法被子類繼承到,所以就沒辦法重寫。
public class Animal {
final void move() { }
}
由于父類 Animal 中的 move() 是 final 的,所以子類在嘗試重寫該方法的時(shí)候就出現(xiàn)編譯錯(cuò)誤了!

同樣的,如果一個(gè)方法是 static 的,也不允許重寫,因?yàn)殪o態(tài)方法可用于父類以及子類的所有實(shí)例。
public class Animal {
final void move() { }
}
重寫的目的在于根據(jù)對(duì)象的類型不同而表現(xiàn)出多態(tài),而靜態(tài)方法不需要?jiǎng)?chuàng)建對(duì)象就可以使用。沒有了對(duì)象,重寫所需要的“對(duì)象的類型”也就沒有存在的意義了。

04、重寫方法的要求
規(guī)則三:重寫的方法必須有相同的參數(shù)列表。
public class Animal {
void eat(String food) { }
}
Dog 類中的 eat() 方法保持了父類方法 eat() 的同一個(gè)調(diào)調(diào),都有一個(gè)參數(shù)——String 類型的 food。
public class Dog extends Animal {
public void eat(String food) { }
}
一旦子類沒有按照這個(gè)規(guī)則來,比如說增加了一個(gè)參數(shù):
public class Dog extends Animal {
public void eat(String food, int amount) { }
}
這就不再是重寫的范疇了,當(dāng)然也不是重載的范疇,因?yàn)橹剌d考慮的是同一個(gè)類。
規(guī)則四:重寫的方法必須返回相同的類型。
父類沒有返回類型:
public class Animal {
void eat(String food) { }
}
子類嘗試返回 String:
public class Dog extends Animal {
public String eat(String food) {
return null;
}
}
于是就編譯出錯(cuò)了(返回類型不兼容)。

規(guī)則五:重寫的方法不能使用限制等級(jí)更嚴(yán)格的權(quán)限修飾符。
可以這樣來理解:
- 如果被重寫的方法是 default,那么重寫的方法可以是 default、protected 或者 public。
- 如果被重寫的方法是 protected,那么重寫的方法只能是 protected 或者 public。
- 如果被重寫的方法是 public, 那么重寫的方法就只能是 public。
舉個(gè)例子,父類中的方法是 protected:
public class Animal {
protected void eat() { }
}
子類中的方法可以是 public:
public class Dog extends Animal {
public void eat() { }
}
如果子類中的方法用了更嚴(yán)格的權(quán)限修飾符,編譯器就報(bào)錯(cuò)了。

規(guī)則六:重寫后的方法不能拋出比父類中更高級(jí)別的異常。
舉例來說,如果父類中的方法拋出的是 IOException,那么子類中重寫的方法不能拋出 Exception,可以是 IOException 的子類或者不拋出任何異常。這條規(guī)則只適用于可檢查的異常。
可檢查(checked)異常必須在源代碼中顯式地進(jìn)行捕獲處理,不檢查(unchecked)異常就是所謂的運(yùn)行時(shí)異常,比如說 NullPointerException、ArrayIndexOutOfBoundsException 之類的,不會(huì)在編譯器強(qiáng)制要求。
父類拋出 IOException:
public class Animal {
protected void eat() throws IOException { }
}
子類拋出 FileNotFoundException 是可以滿足重寫的規(guī)則的,因?yàn)?FileNotFoundException 是 IOException 的子類。
public class Dog extends Animal {
public void eat() throws FileNotFoundException { }
}
如果子類拋出了一個(gè)新的異常,并且是一個(gè) checked 異常:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, InterruptedException { }
}
那編譯器就會(huì)提示錯(cuò)誤:
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()無(wú)法覆蓋com.itwanger.overriding.Animal中的eat()
被覆蓋的方法未拋出java.lang.InterruptedException
但如果子類拋出的是一個(gè) unchecked 異常,那就沒有沖突:
public class Dog extends Animal {
public void eat() throws FileNotFoundException, IllegalArgumentException { }
}
如果子類拋出的是一個(gè)更高級(jí)別的異常:
public class Dog extends Animal {
public void eat() throws Exception { }
}
編譯器同樣會(huì)提示錯(cuò)誤,因?yàn)?Exception 是 IOException 的父類。
Error:(9, 16) java: com.itwanger.overriding.Dog中的eat()無(wú)法覆蓋com.itwanger.overriding.Animal中的eat()
被覆蓋的方法未拋出java.lang.Exception
05、如何調(diào)用被重寫的方法?
規(guī)則七:可以在子類中通過 super 關(guān)鍵字來調(diào)用父類中被重寫的方法。
子類繼承父類的方法而不是重新實(shí)現(xiàn)是很常見的一種做法,在這種情況下,可以按照下面的形式調(diào)用父類的方法:
super.overriddenMethodName();
來看例子。
public class Animal {
protected void eat() { }
}
子類重寫了 eat() 方法,然后在子類的 eat() 方法中,可以在方法體的第一行通過 super.eat() 調(diào)用父類的方法,然后再增加屬于自己的代碼。
public class Dog extends Animal {
public void eat() {
super.eat();
// Dog-eat
}
}
06、重寫和構(gòu)造方法
規(guī)則八:構(gòu)造方法不能被重寫。
因?yàn)闃?gòu)造方法很特殊,而且子類的構(gòu)造方法不能和父類的構(gòu)造方法同名(類名不同),所以構(gòu)造方法和重寫之間沒有任何關(guān)系。
07、重寫和抽象方法
規(guī)則九:如果一個(gè)類繼承了抽象類,抽象類中的抽象方法必須在子類中被重寫。
先來看這樣一個(gè)接口類:
public interface Animal {
void move();
}
接口中的方法默認(rèn)都是抽象方法,通過反編譯是可以看得到的:
public interface Animal
{
public abstract void move();
}
如果一個(gè)抽象類實(shí)現(xiàn)了 Animal 接口,move() 方法不是必須被重寫的:
public abstract class AbstractDog implements Animal {
protected abstract void bark();
}
但如果一個(gè)類繼承了抽象類 AbstractDog,那么 Animal 接口中的 move() 方法和抽象類 AbstractDog 中的抽象方法 bark() 都必須被重寫:
public class BullDog extends AbstractDog {
public void move() {}
protected void bark() {}
}
08、重寫和 synchronized 方法
規(guī)則十:synchronized 關(guān)鍵字對(duì)重寫規(guī)則沒有任何影響。
synchronized 關(guān)鍵字用于在多線程環(huán)境中獲取和釋放監(jiān)聽對(duì)象,因此它對(duì)重寫規(guī)則沒有任何影響,這就意味著 synchronized 方法可以去重寫一個(gè)非同步方法。
09、重寫和 strictfp 方法
規(guī)則十一:strictfp 關(guān)鍵字對(duì)重寫規(guī)則沒有任何影響。
如果你想讓浮點(diǎn)運(yùn)算更加精確,而且不會(huì)因?yàn)橛布脚_(tái)的不同導(dǎo)致執(zhí)行的結(jié)果不一致的話,可以在方法上添加 strictfp 關(guān)鍵字。因此 strictfp 關(guān)鍵和重寫規(guī)則無(wú)關(guān)。
到此這篇關(guān)于Java 重寫時(shí)應(yīng)當(dāng)遵守的 11 條規(guī)則的文章就介紹到這了,更多相關(guān)Java 重寫規(guī)則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解 Java繼承關(guān)系下的構(gòu)造方法調(diào)用
這篇文章主要介紹了詳解 Java繼承關(guān)系下的構(gòu)造方法調(diào)用的相關(guān)資料,希望通過本文能幫助到大家,讓大家理解掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10
Hikari連接池使用SpringBoot配置JMX監(jiān)控實(shí)現(xiàn)
Hikari是Spring Boot默認(rèn)的數(shù)據(jù)庫(kù)連接池。區(qū)別于C3P0直接通過連接池對(duì)象獲取各項(xiàng)狀態(tài)指標(biāo),Hikari需要通過JMX來獲取。本文就詳細(xì)的來介紹一下,感興趣的可以了解一下2021-07-07
Java針對(duì)封裝數(shù)組的簡(jiǎn)單復(fù)雜度分析方法
這篇文章主要介紹了Java針對(duì)封裝數(shù)組的簡(jiǎn)單復(fù)雜度分析方法,簡(jiǎn)單講述了java封裝數(shù)組時(shí)間復(fù)雜度分析的原理、實(shí)現(xiàn)方法與操作注意事項(xiàng),需要的朋友可以參考下2020-03-03
java swing 創(chuàng)建一個(gè)簡(jiǎn)單的QQ界面教程
這篇文章主要介紹了java swing 創(chuàng)建一個(gè)簡(jiǎn)單的QQ界面教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
SpringBoot使用Spring-Data-Jpa實(shí)現(xiàn)CRUD操作
這篇文章主要為大家詳細(xì)介紹了SpringBoot使用Spring-Data-Jpa實(shí)現(xiàn)CRUD操作,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
Springboot通過ObjectMapper配置json序列化詳解
SpringBoot默認(rèn)集成Jackson庫(kù),其中ObjectMapper類是核心,用于Java對(duì)象與JSON字符串的互轉(zhuǎn),提供配置序列化特性、注冊(cè)模塊等方法,在SpringBoot中可以全局配置JSON格式,如日期格式化、將Long轉(zhuǎn)為字符串,還可以配置序列化時(shí)的各種規(guī)則,感興趣的可以了解一下2024-10-10
Java網(wǎng)絡(luò)編程之基于TCP協(xié)議
本文主要將Java基于TCP的網(wǎng)絡(luò)編程主要分解成5個(gè)功能:功能分解1:單向通信功能分解,2:雙向通信功能分解,3:對(duì)象流傳送功能分解,4:加入完整的處理異常方式功能分解,5:多線程接收用戶請(qǐng)求,需要的朋友可以參考下2021-05-05
java中金額元轉(zhuǎn)萬(wàn)元工具類的實(shí)例
這篇文章主要介紹了java中金額元轉(zhuǎn)萬(wàn)元工具類的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02

