關於全部Java系列文章面向有必定基礎的童鞋,所寫每一篇但願有必定含金量,有些內容可能會從Java整個語法全局考慮穿插後續要講解的內容以成系統,若不理解,請看完後再學習。上一節咱們講解完了final關鍵字,本節咱們繼續來對比講解Java和C#中的重寫,兩者語言的重寫區分很是清晰,Java子類中基類方法簽名同樣或經過註解@Override顯式聲明,C#中基類經過virtual關鍵字修飾,子類經過ovveride關鍵字表示重寫,具體細節請往下看。ide
既然是重寫必然就涉及到繼承,咱們首先來看看Java中的重寫是怎樣的呢?以下:學習
public class Main { public void f() { System.out.println("Main.f"); } public static void main(String[] args) { Main main = new Sub(); main.f(); } } class Sub extends Main { public void f() { System.out.println("Sub.f"); } }
當調用基類的f方法時,此時發現已被子類所重寫,因此如上正常打印出Sub.f,要是咱們將上述基類中方法修改成私有的呢spa
可能咱們期待輸出子類中的打印結果,可是修改成私有後,說明此時對子類再也不可見,也就至關於使用了final,在這種狀況下,子類中方法則是一個全新的方法,很顯然說明:只有非私有方法才能夠被重寫。對於這種狀況下編譯不會報錯, 可是也不會按照咱們所指望的結果來執行,因此建議對於基類中的私有方法命名爲和子類不一樣的名字,爲了讓重寫一目瞭然或更加明確,在1.5版本發佈了註解功能,咱們能夠經過註解來顯式聲明要重寫基類方法,若基類爲私有,此時經過註解則會編譯報錯,由於找不到要重寫的方法,這種體驗更加友好,好比以下:code
public class Main { private void f() { System.out.println("Main.f"); } public static void main(String[] args) { Main main = new Sub(); main.f(); } } class Sub extends Main { //編譯錯誤,未找到基類(超類)中要重寫的方法 @Override public void f() { System.out.println("Sub.f"); } }
觸類旁通,咱們來思考一個問題,是否是方法簽名一致,子類就能夠重寫基類方法呢?很顯然不是,如果靜態方法,必然不能被重寫,若是經過註解@Override聲明那麼必然編譯報錯,不然調用基類方法,對於接口中的靜態方法同理。因此仍是建議使用註解來聲明重寫。那麼爲何經過註解顯式聲明重寫基類方法或經過關鍵字final修飾方法就會在編譯階段報錯呢?由於它們在編譯階段就完成了靜態綁定,而不是運行時動態綁定。問題又來了,上述咱們講解到若在子類中不經過註解顯式聲明重寫,同時在基類中方法私有,此時必定能夠編譯經過(上述已演示),而且會調用基類方法並打印出結果,事實狀況必定是這樣嗎?很顯然也不是如此,以下示例:blog
class Super { private void f() { System.out.println("Super.f"); } } class Derived extends Super { public void f() { System.out.println("Derived.f"); } public static void main(String[] args) { Super aSuper = new Derived(); //編譯報錯(由於基類方法私有) aSuper.f(); } }
初一看,這不是同樣麼,實際上是不同,上述能夠那是由於調用方在基類裏面,固然能夠調用內部的私有方法,如上狀況只對基類內部私有, 固然也就不能調用,這裏就又引出一個問題,是否是聲明爲基類的私有方法,子類就沒法進行重寫呢?根據咱們上述打印的結果來看,理論上不可行,事實狀況是能夠的,經過內部類(後續會出文章詳細講解)來實現。繼承
class Main { private void f() { System.out.println("Main.f"); } class Inner extends Main { private void f() { System.out.println("Inner.f"); } } public static void main(String args[]) { //內部類實例必須經過外部類實例建立 Main outer = new Main(); Inner inner = outer.new Inner(); //內部類能夠在內部訪問外部的全部成員(包括私有) inner.f(); // 調用外部類方法 outer = inner; outer.f(); } }
C#若明確須要重寫,那麼基類方法聲明爲虛有的virtual,子類經過ovverride關鍵字修飾方法達到重寫目的,若沒有這兩個關鍵字,和Java中同樣只是方法簽名一致,那麼說明編譯器會提醒是否經過new關鍵字來代表隱藏基類的方法接口
class Program { public void F() { Console.WriteLine("Main.f"); } static void Main(string[] args) { Program program = new Sub(); program.F(); Console.ReadKey(); } } class Sub : Program { public new void F() { Console.WriteLine("Sub.f"); } }
Java和C#中的重寫區分度很是清晰,Java中只要方法簽名一致就能夠達到重寫,不過建議經過註解方法來顯式聲明重寫以避免引發沒必要要的問題,同時,即便基類方法私有,咱們也可藉助於內部類來實現重寫。編譯器