【Java】重載和重寫


前言

在程序設計中經常會遇到要對方法進行重載或者重寫的情況,下面就介紹一下重載和重寫。

重載(Overloade)

重載出現的原因

任何程序設計語言都具備的一項重要特性就是對名字的運用。方法名就是給某個動作取的名字。通過使用名字,我們可以引用所有對象和方法。名字起的好可以使程序更易於理解和修改。

在大多數程序設計語言中要求為每個方法提供唯一的標識符。不能使用print()的方法顯示了整數之后,又用一個名為print()的方法顯示浮點數。即每個方法都要有唯一的名稱。這是迫使出現重載方法的理由之一。若是print()函數可以被重載了,那么就既可以輸出整數也可以輸出浮點數。又例如,我們要計算兩個整數相加,我們可以設計方法為int add(int a, int b)。調用add(10,10)我們就可以知道是計算兩個整數相加。此時,我們又想計算兩個浮點數相加,因為add見名知意所以我們繼續使用這個名字,那么就需要方法double add(double a, double c)。於是,add()方法就被重載了。

在Java(和C++)里,構造器是強制重載方法出現的另一個原因。構造器的名字由類名決定,那么就只能有一個構造器。但是,又想使用多種方式創建對象又該怎么辦呢?那么就只有重載構造器,使得同名不同參的構造器同時存在。

重載的規則

方法重載是在一個類里面,方法名相同,而參數不同,對返回值沒有強制要求可以相同也可以不同。方法重載需要注意一下幾點:

  • 被重載的方法必須改變參數列表(參數個數或者類型不一樣)
  • 被重載的方法不介意改變返回類型和訪問修飾符
  • 被重載的方法可以聲明新的或者更廣的檢查異常
  • 方法能夠在同一個類中或者在一個子類中被重載
  • 不可以返回值類型作為分區重載函數的標准

區分重載方法

每個重載的方法都有獨一無二的參數類型列表。所以在區分重載方法時,只能以類名和方法的形參列表作為標准

那為什么不能使用方法的返回值來區分呢?

比如下面兩個方法,雖然它們有相同的名字和形式參數,但是卻很容易區分它們

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

只要編譯器可以根據語境明確判斷出語義,比如在int x = f()中,那么的確可以根據此區分方法。不過,有時你並不關心方法的返回值,你想要的是方法調用的其他效果,這時你可能會調用方法而忽略返回值。所以,向下面這樣的調用方法:

f();

此時Java該怎樣判斷調用的是哪個方法呢?別人也無法理解這個代碼的含義。因此,依據方法的返回值來區分重載方法是行不通的。

重寫(Override)

重寫出現的原因

先看一個例子

class Animal{
    public void printWhoIAm(){System.out.println("Animal")}
}
public class Dog extends Animal{
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.printWhoIAm();
    }
} 
/*
output:
Animal
*/

當dog調用printWhoIAm()方法時,其實希望的是輸出“dog”,而不是Animal。要實現輸出“Dog”,想到了重載,可是重載要求被重載的方法具有不同的形參列表。這個方法不得行。dog調用的printWhoIAm()是父類中的,在子類中若是可以重寫這個方法,那么就可以實現目的了。於是,重寫(覆寫)便產生了,為了解決父類方法在子類中不適用,而讓子類重寫方法的方式

我們解決以上代碼需求如下:

class Animal{
    public void printWhoIAm(){
        System.out.println("Animal")
    }
}
public class Dog extends Animal{
    //加上注解@Override可以強制進行重寫的檢查 防止自己重寫錯誤
    @Override
    public void printWhoIAm(){
        System.out.println("Dog")
    }
    
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.printWhoIAm();
    }
} 
/*
output:
Dog
*/

重寫的規則

  • 重寫是對父類允許訪問的方法的實現過程進行重新編寫,返回值不變或者為子類、形參列表不能改變並且訪問控制權限不能嚴於父類。父類為default包訪問權限,則子類就為public或者default;若父類是public,則子類必須為public。

  • 子類可以重寫父類的除了構造器的任何方法。構造器是和類名相同的,不能被子類繼承,因此也不可以被重寫。

  • 重寫方法不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的異常。例如: 父類的一個方法申明了一個檢查異常 IOException,但是在重寫這個方法的時候不能拋出 Exception 異常,因為 Exception 是 IOException 的父類,只能拋出 IOException 的子類異常。

子類可以重寫父類中訪問控制權限為private的方法嗎?

答案是不可以。父類中的private方法對子類來說是不可見的,就算子類中完全按照重寫要求定義方法,也不能算重寫父類中的方法,實際上只是子類新增的一個方法。所以,只有非private方法才可以被重寫。

super.方法()和this.方法()的區別

子類若是重寫了父類的方法,那么父類原來的這個方法還可以被調用嗎?

答案是可以的,使用super對父類的方法進行調用。

class Animal{
    public void printWhoIAm(){System.out.println("Animal")}
}
public class Dog extends Animal{
    //加上注解@Override可以強制進行重寫的檢查 防止自己重寫錯誤
    @Override
    public void printWhoIAm(){System.out.println("Dog")}
    public void print(){
        super.printWhoIAm();
        printWhoIAm();// this.printWhoIAm();
    }
    public static void main(String args[]){
        Dog dog = new Dog();
        dog.print();
    }
} 
/*
output:
Animal
Dog
*/

使用this.方法()會先在本類中查找是否存在要調用的方法,如果不存在則查找父類中是否具備此方法。如果有則調用,否則出現編譯時錯誤。

使用super.方法()會明確表示調用父類中的方法,直接去父類尋找要調用的方法。

重載和重寫的區別

區別 重載 重寫
參數列表 必須改 一定不能改
返回類型 可以修改 一定不能改
訪問控制權限 可以修改 不能比父類嚴格
異常 可以修改 可以減少或刪除,一定不能拋出新的或者更廣的異常
發生范圍 可以在一個類中也可以在子類中 在子類中

小結

需要注意的是重載和重寫的定義形式。引用菜鳥教程的兩句話和一張圖結束。

  • 方法重載是一個類中定義了多個方法名相同,而他們的參數的數量不同或數量相同而類型和次序不同,則稱為方法的重載(Overloading)。

  • 方法重寫是在子類存在方法與父類的方法的名字相同,而且參數的個數與類型一樣,返回值也一樣的方法,就稱為重寫(Overriding)

參考:

[1] Eckel B. Java編程思想(第四版)[M]. 北京: 機械工業出版社, 2007

[2] 菜鳥教程. Java 重寫(Override)與重載(Overload) |[EB/OL]. /2019-02-18. https://www.runoob.com/java/java-override-overload.html.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM