banner
lMingyul

lMingyul

记录穿过自己的万物
jike

重載與重寫

記錄一下自己在學習 Java 的一些筆記。

重載#

重載: 重載指的是方法的重載,重載的特徵就是兩個或多個方法具有同名。

經典的重載方法#

重載多用於構造器方法,因為構造器作用是初始化構建對象的,構造器的名字必須與類名相同,這就形成經典的無參構造器與有參構造器這一對重載方法。

下面給出了示例:

/**
 * @author mingyu
 */
public class User {

    private Integer id;

    private String userName;
		
  	//  無參構造器
    public User() {
    }
		
  	// 單個參數的構造器
    public User(Integer id) {
        this.id = id;
    }

  	// 全參構造器
    public User(Integer id, String userName) {
        this.id = id;
        this.userName = userName;
    }

}

為什麼需要重載#

我們都知道,Java 中最重要的一個概念就是:對象。那方法就是對象的一個個行為。一個對象在做相同名字的行為也可以是在做不同的事情,比如:小明打麻將。

字面意思:小明在和其他人一起玩麻將這類娛樂活動

其他意思:小明在 "打" 一個名字叫 "麻將" 的人

所以說,現實生活中語言當中的歧義也會出現在代碼裡。

還比如說,一個人在吃東西,我給他什麼,他就在吃什麼,我給他麵條,他的行為就是吃麵條,我給他米飯,他就是在吃米飯,但是他的行為都叫吃東西

總結:重載在代碼當中是很必要的。

重載的區分#

如果不同的方法都是一個名字,要怎麼分辨它們呢?

分辨重載的重要原則:每個重載的方法必須有獨一無二的參數類型列表(即每個方法都有與其他同名方法不同的入參)

那不同的參數列表,到底哪裡不同呢?

參數類型的不同#

public class Test {

    public static void main(String[] args) {
      	// age 的類型不同可以區分兩個同名的方法
        getPerson("mingyu", 18);
        getPerson("mingyu", "18");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "int_age: " + age);
    }

    static void getPerson(String name, String age) {
        System.out.println("name: " + name + ", " + "String_age: " + age);
    }

}

輸出結果:

name: mingyu, int_age: 18
name: mingyu, String_age: 18

參數順序的不同#

雖然參數順序不同可以區分同名的重載方法,但是不推薦使用這種使用方式進行區分,因為這樣寫代碼很難維護

public class Test {

    public static void main(String[] args) {
        getPerson("mingyu", 18);
        getPerson(18,"mingyu");
    }

    static void getPerson(String name, int age) {
        System.out.println("name: " + name + ", " + "behind_age: " + age);
    }

    static void getPerson(int age, String name) {
        System.out.println("name: " + name + ", " + "first_age: " + age);
    }

}

輸出結果:

name: mingyu, behind_age: 18
name: mingyu, first_age: 18

返回值區分重載方法#

除了參數列表的類型、順序可以區分方法外,我們能否用方法的返回值來區分呢?

答案是不行的,下面給出了例子。

 void f() {}
    
 int f() { return 1; }

當我們只想調用 f() 方法,但不需要該方法的返回值(如 System.out.println 方法),這時如果只是調用方法 f(),Java 是無法區分我們需要調用的是哪個方法的。

基本類型的重載#

對於只有基本類型不同的重載方法,會出現基本類型可以從小類型自動提升到較大類型的情況

public class Test {

    public static void main(String[] args) {
        int x = 5;
        checkBasicTypes(x);
    }

    static void checkBasicTypes(long x) {
        System.out.println("Type long: " + x);
    }

    static void checkBasicTypes(float x) {
        System.out.println("Type float: " + x);
    }

    static void checkBasicTypes(double x) {
        System.out.println("Type double: " + x);
    }

}

輸出結果:

Type long: 5

變量 x 為 int 類型,但是 checkBasicTypes() 方法並沒有 int 類型的入參,當程序運行時,會找到類型比 int 類型大的方法進行調用,即傳入數據類型小於方法的參數類型,傳入的數據類型會自動被提升。( int -> long)

重寫#

重寫一般出現在父子類關係之間,父類與子類有兩個名稱與參數列表都相同的方法,由於它們具有相同的方法名稱,所以在方法調用的時候,子類的方法會覆蓋同名的父類方法。

下面是重寫的一個例子

public class Test {

    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.say();
    }
}

class Animal {
    public void say() {
        System.out.println("I'm animal.");
    }
}

class Dog extends Animal {

    @Override
    public void say() {
        System.out.println("I'm Dog.");
    }

    public void eat() {
        System.out.println("Dog like eat meat.");
    }
}

輸出結果:

I'm Dog.

上面的例子中,父類與子類都定義了 say() 方法,實際上稱之為子類重寫了父類的 say()方法。

重寫方法之後,當我們調用子類對象的 say() 方法,儘管 Dog 對象的類型是 Animal ,Java 依然會調用 Dog 的 say() 方法,因為子類的方法會覆蓋同名的父類方法。

重寫的原則#

如果需要重寫方法,需要滿足里式替換原則:

  • 子類方法的訪問權限必須大於等於父類方法
    • 如父類方法修飾符為 protected,那子類方法的修飾符只能是 protected 或 public
  • 子類方法的返回類型必須是父類方法返回類型或為其子類型。
    • 如 B extends A : 父方法返回類型為 A,那麼子類方法可以返回 A 類型,也可以是 B 類型
  • 子類方法拋出的異常類型必須是父類拋出異常類型或為其子類型。

@Override 註解#

@Override 註解並不是 Java 中的關鍵字,但可以當做關鍵字一樣使用,如果在重寫方法上加上這個註解,編譯器就會幫助你檢查是否滿足上面的三個限制條件,檢測這個重寫方法是否合法。有時候還可以有效的防止意外重載。

參考資料#

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。