<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          方法重載與方法重寫,差點讓我妹迷了路

          共 5932字,需瀏覽 12分鐘

           ·

          2020-12-26 18:08

          01、開篇

          入冬的夜,總是來得特別的早。我靜靜地站在陽臺,目光所及之處,不過是若隱若現(xiàn)的鋼筋混凝土,還有那毫無情調(diào)的燈光。

          “哥,別站在那發(fā)呆了。今天學(xué)啥啊,七點半我就要回學(xué)校了,留給你的時間不多了,你要抓緊哦。”三妹傲嬌的聲音一下子把我從游離的狀態(tài)拉回到了現(xiàn)實。

          “今天要學(xué)習(xí) Java 中的方法重載與方法重寫。”我迅速地走到電腦前面,打開一份 Excel 文檔,看了一下《教妹學(xué) Java》的進(jìn)度,然后對三妹說。

          “如果一個類有多個名字相同但參數(shù)個數(shù)不同的方法,我們通常稱這些方法為方法重載。”我面帶著樸實無華的微笑繼續(xù)說,“如果方法的功能是一樣的,但參數(shù)不同,使用相同的名字可以提高程序的可讀性。”

          “如果子類具有和父類一樣的方法(參數(shù)相同、返回類型相同、方法名相同,但方法體可能不同),我們稱之為方法重寫。方法重寫用于提供父類已經(jīng)聲明的方法的特殊實現(xiàn),是實現(xiàn)多態(tài)的基礎(chǔ)條件。”

          “只不過,方法重載與方法重寫在名字上很相似,就像是兄弟倆,導(dǎo)致初學(xué)者經(jīng)常把它們倆搞混。”

          “方法重載的英文名叫 Overloading,方法重寫的英文名叫 Overriding,因此,不僅中文名很相近,英文名之間也很相近,這就更容易讓初學(xué)者搞混了。”

          “但兩者其實是完全不同的!通過下面這張圖,你就能看得一清二楚。”

          話音剛落,我就在 IDEA 中噼里啪啦地敲了起來。兩段代碼,分別是方法重寫和方法重載。然后,把這兩段代碼截圖到 draw.io(一個很漂亮的在線畫圖網(wǎng)站)上,加了一些文字說明。最后,打開 Photoscape X,把兩張圖片合并到了一起。

          02、方法重載

          “三妹,你仔細(xì)聽哦。”我緩了一口氣后繼續(xù)說道。

          “在 Java 中,有兩種方式可以達(dá)到方法重載的目的。”

          “第一,改變參數(shù)的數(shù)目。來看下面這段代碼。”

          public?class?OverloadingByParamNum?{
          ????public?static?void?main(String[]?args)?{
          ????????System.out.println(Adder.add(10,?19));
          ????????System.out.println(Adder.add(10,?19,?20));
          ????}
          }

          class?Adder?{
          ????static?int?add(int?a,?int?b)?{
          ????????return?a?+?b;
          ????}

          ????static?int?add(int?a,?int?b,?int?c)?{
          ????????return?a?+?b?+?c;
          ????}
          }??

          “Adder 類有兩個方法,第一個 add() 方法有兩個參數(shù),在調(diào)用的時候可以傳遞兩個參數(shù);第二個 add() 方法有三個參數(shù),在調(diào)用的時候可以傳遞三個參數(shù)。”

          “二哥,這樣的代碼不會顯得啰嗦嗎?如果有四個參數(shù)的時候就再追加一個方法?”三妹突然提了一個很尖銳的問題。

          “那倒是,這個例子只是為了說明方法重載的一種類型。如果參數(shù)類型相同的話,Java 提供了可變參數(shù)的方式,就像下面這樣。”

          static?int?add(int?...?args)?{
          ????int?sum?=?0;
          ????for?(?int?a:?args)?{
          ????????sum?+=?a;
          ????}
          ????return?sum;
          }

          “第二,通過改變參數(shù)類型,也可以達(dá)到方法重載的目的。來看下面這段代碼。”

          public?class?OverloadingByParamType?{
          ????public?static?void?main(String[]?args)?{
          ????????System.out.println(Adder.add(10,?19));
          ????????System.out.println(Adder.add(10.1,?19.2));
          ????}
          }

          class?Adder?{
          ????static?int?add(int?a,?int?b)?{
          ????????return?a?+?b;
          ????}

          ????static?double?add(double?a,?double?b)?{
          ????????return?a?+?b;
          ????}
          }

          “Adder 類有兩個方法,第一個 add() 方法的參數(shù)類型為 int,第二個 add() 方法的參數(shù)類型為 double。”

          “二哥,改變參數(shù)的數(shù)目和類型都可以實現(xiàn)方法重載,為什么改變方法的返回值類型就不可以呢?”三妹很能抓住問題的重點嘛。

          “因為僅僅改變返回值類型的話,會把編譯器搞懵逼的。”我略帶調(diào)皮的口吻回答她。

          “編譯時報錯優(yōu)于運行時報錯,所以當(dāng)兩個方法的名字相同,參數(shù)個數(shù)和類型也相同的時候,雖然返回值類型不同,但依然會提示方法已經(jīng)被定義的錯誤。”

          “你想啊,三妹。我們在調(diào)用一個方法的時候,可以指定返回值類型,也可以不指定。當(dāng)不指定的時候,直接指定 add(1, 2) 的時候,編譯器就不知道該調(diào)用返回 int 的 add() 方法還是返回 double 的 add() 方法,產(chǎn)生了歧義。”

          “方法的返回值只是作為方法運行后的一個狀態(tài),它是保持方法的調(diào)用者和被調(diào)用者進(jìn)行通信的一個紐帶,但并不能作為某個方法的‘標(biāo)識’。”

          “二哥,我想到了一個點,main() 方法可以重載嗎?”

          “三妹,這是個好問題啊!答案是肯定的,畢竟 main() 方法也是個方法,只不過,Java 虛擬機在運行的時候只會調(diào)用帶有 String 數(shù)組的那個 main() 方法。”

          public?class?OverloadingMain?{
          ????public?static?void?main(String[]?args)?{
          ????????System.out.println("String[]?args");
          ????}

          ????public?static?void?main(String?args)?{
          ????????System.out.println("String?args");
          ????}

          ????public?static?void?main()?{
          ????????System.out.println("無參");
          ????}
          }

          “第一個 main() 方法的參數(shù)形式為 String[] args,是最標(biāo)準(zhǔn)的寫法;第二個 main() 方法的參數(shù)形式為 String args,少了中括號;第三個 main() 方法沒有參數(shù)。”

          “來看一下程序的輸出結(jié)果。”

          String[]?args

          “從結(jié)果中,我們可以看得出,盡管 main() 方法可以重載,但程序只認(rèn)標(biāo)準(zhǔn)寫法。”

          “由于可以通過改變參數(shù)類型的方式實現(xiàn)方法重載,那么當(dāng)傳遞的參數(shù)沒有找到匹配的方法時,就會發(fā)生隱式的類型轉(zhuǎn)換。”

          “如上圖所示,byte 可以向上轉(zhuǎn)換為 short、int、long、float 和 double,short 可以向上轉(zhuǎn)換為 int、long、float 和 double,char 可以向上轉(zhuǎn)換為 int、long、float 和 double,依次類推。”

          “三妹,來看下面這個示例。”

          public?class?OverloadingTypePromotion?{
          ????void?sum(int?a,?long?b)?{
          ????????System.out.println(a?+?b);
          ????}

          ????void?sum(int?a,?int?b,?int?c)?{
          ????????System.out.println(a?+?b?+?c);
          ????}

          ????public?static?void?main(String?args[])?{
          ????????OverloadingTypePromotion?obj?=?new?OverloadingTypePromotion();
          ????????obj.sum(20,?20);
          ????????obj.sum(20,?20,?20);
          ????}
          }

          “執(zhí)行 obj.sum(20, 20) 的時候,發(fā)現(xiàn)沒有 sum(int a, int b) 的方法,所以此時第二個 20 向上轉(zhuǎn)型為 long,所以調(diào)用的是 sum(int a, long b) 的方法。”

          “再來看一個示例。”

          public?class?OverloadingTypePromotion1?{
          ????void?sum(int?a,?int?b)?{
          ????????System.out.println("int");
          ????}

          ????void?sum(long?a,?long?b)?{
          ????????System.out.println("long");
          ????}

          ????public?static?void?main(String?args[])?{
          ????????OverloadingTypePromotion1?obj?=?new?OverloadingTypePromotion1();
          ????????obj.sum(20,?20);
          ????}
          }

          “執(zhí)行 obj.sum(20, 20) 的時候,發(fā)現(xiàn)有 sum(int a, int b) 的方法,所以就不會向上轉(zhuǎn)型為 long,調(diào)用 sum(long a, long b)。”

          “來看一下程序的輸出結(jié)果。”

          int

          “繼續(xù)來看示例。”

          public?class?OverloadingTypePromotion2?{
          ????void?sum(long?a,?int?b)?{
          ????????System.out.println("long?int");
          ????}

          ????void?sum(int?a,?long?b)?{
          ????????System.out.println("int?long");
          ????}

          ????public?static?void?main(String?args[])?{
          ????????OverloadingTypePromotion2?obj?=?new?OverloadingTypePromotion2();
          ????????obj.sum(20,?20);
          ????}
          }

          “二哥,我又想到一個問題。當(dāng)有兩個方法 sum(long a, int b)sum(int a, long b),參數(shù)個數(shù)相同,參數(shù)類型相同,只不過位置不同的時候,會發(fā)生什么呢?”

          “當(dāng)通過 obj.sum(20, 20) 來調(diào)用 sum 方法的時候,編譯器會提示錯誤。”

          “不明確,編譯器會很為難,究竟是把第一個 20 從 int 轉(zhuǎn)成 long 呢,還是把第二個 20 從 int 轉(zhuǎn)成 long,智障了!所以,不能寫這樣讓編譯器左右為難的代碼。”

          03、方法重寫

          “三妹,累嗎?我們稍微休息一下吧。”我把眼鏡摘下來,放到桌子上,閉上了眼睛,開始胡思亂想起來。

          2000 年,周杰倫橫空出世,讓青黃不接的唱片行業(yè)為之一振,由此開啟了新一代天王爭霸的黃金時代。2020 年,杰倫胖了,也貪玩了,一年出一張單曲都變得可遇不可求。

          20 年前,程序員很稀有;20 年后,程序員內(nèi)卷了。時間永遠(yuǎn)不會停下腳步,明年會不會好起來呢?

          “哥,醒醒,你就說休息一會,沒說睡著啊。趕緊,我還有半個小時就要走了。”

          我戴上眼鏡,對三妹繼續(xù)說道:“在 Java 中,方法重寫需要滿足以下三個規(guī)則。”

          • 重寫的方法必須和父類中的方法有著相同的名字;
          • 重寫的方法必須和父類中的方法有著相同的參數(shù);
          • 必須是 is-a 的關(guān)系(繼承關(guān)系)。

          “來看下面這段代碼。”

          public?class?Bike?extends?Vehicle?{
          ????public?static?void?main(String[]?args)?{
          ????????Bike?bike?=?new?Bike();
          ????????bike.run();
          ????}
          }

          class?Vehicle?{
          ????void?run()?{
          ????????System.out.println("車輛在跑");
          ????}
          }

          “來看一下程序的輸出結(jié)果。”

          車輛在跑

          “Bike is-a Vehicle,自行車是一種車,沒錯。Vehicle 類有一個 run() 的方法,也就是說車輛可以跑,Bike 繼承了 Vehicle,也可以跑。但如果 Bike 沒有重寫 run() 方法的話,自行車就只能是‘車輛在跑’,而不是‘自行車在跑’,對吧?”

          “如果有了方法重寫,一切就好辦了。”

          public?class?Bike?extends?Vehicle?{
          ????@Override
          ????void?run()?{
          ????????System.out.println("自行車在跑");
          ????}

          ????public?static?void?main(String[]?args)?{
          ????????Bike?bike?=?new?Bike();
          ????????bike.run();
          ????}
          }

          class?Vehicle?{
          ????void?run()?{
          ????????System.out.println("車輛在跑");
          ????}
          }

          我把鼠標(biāo)移動到 Bike 類的 run() 方法,對三妹說:“你看,在方法重寫的時候,IDEA 會建議使用 @Override 注解,顯式的表示這是一個重寫后的方法,盡管可以缺省。”

          “來看一下程序的輸出結(jié)果。”

          自行車在跑

          “Bike 重寫了 run() 方法,也就意味著,Bike 可以跑出自己的風(fēng)格。”

          04、總結(jié)

          “好了,三妹,我來簡單做個總結(jié)。”我瞥了一眼電腦右上角的時鐘,離三妹離開的時間不到 10 分鐘了。

          “首先來說一下方法重載時的注意事項,‘兩同一不同’。”

          “‘兩同’:在同一個類,方法名相同。”

          “‘一不同’:參數(shù)不同。”

          “再來說一下方法重寫時的注意事項,‘兩同一小一大’。”

          “‘兩同’:方法名相同,參數(shù)相同。”

          “‘一小’:子類方法聲明的異常類型要比父類小一些或者相等。”

          “‘一大’:子類方法的訪問權(quán)限應(yīng)該比父類的更大或者相等。”

          “記住了吧?三妹。帶上口罩,拿好手機,咱準(zhǔn)備出門吧。”今天限號,沒法開車送三妹去學(xué)校了。

          “記住了哥,你別忘了發(fā)文的時候讓讀者點贊哦。”

          瀏覽 113
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一区视频在线 | 欧洲成人性爱视频 | 青青草强奸视频 | 欧美操逼一级 | 玖玖视频在线资源一区二区三区四区 |