你好!您已經使用過 Java 方法並且對它們了解很多。方法重寫的工作原理 - 1您肯定遇到過一個類,該類包含許多名稱相同但參數列表不同的方法。您會記得在那些情況下我們使用了方法重載。今天我們來看看不同的情況。想像一下,我們有一個通用方法,但它應該根據在哪個類中調用它來做不同的事情。我們如何實現這種行為?為了理解這一點,讓我們以Animal代表動物的父類為例,並speak在其中創建一個方法:
public class Animal {

   public void speak() {

       System.out.println("Hello!");
   }
}
雖然我們剛剛開始編寫我們的程序,但您可能會看到一個潛在的問題:世界上有很多動物,它們“說話”的方式各不相同:貓叫、鴨叫、蛇嘶等等。我們的目標很簡單:方法重寫的工作原理 - 2我們想避免創造一堆說話的方法。我們不希望創建meow()用於喵喵叫、hiss()嘶嘶聲等的方法,而是希望在調用該方法時蛇發出嘶嘶聲、貓喵喵叫、狗吠叫speak()。我們可以使用方法覆蓋輕鬆實現這一點。維基百科對這個術語的解釋如下:Method overriding,在面向對象編程中,是一種語言功能,它允許子類或子類提供其超類或父類之一已經提供的方法的特定實現。這基本上是正確的。重寫允許您採用父類的某些方法並在每個派生類中編寫您自己的實現。子類中的新實現“替換”了父類中的實現。讓我們通過一個例子看看這是什麼樣子的。讓我們創建我們Animal班級的 4 個後代:
public class Bear extends Animal {
   @Override
   public void speak() {
       System.out.println("Growl!");
   }
}
public class Cat extends Animal {

   @Override
   public void speak() {
       System.out.println("Meow!");
   }
}

public class Dog extends Animal {

   @Override
   public void speak() {
       System.out.println("Woof!");
   }
}


public class Snake extends Animal {

   @Override
   public void speak() {
       System.out.println("Hiss!");
   }
}
這是未來的一個小技巧:要覆蓋父類的方法,請進入IntelliJ IDE 中派生類的代碼,按Ctrl +O,然後從菜單中選擇覆蓋方法...。從一開始就習慣使用熱鍵。他們將加快編碼速度!為了獲得所需的行為,我們做了一些事情:
  1. 在每個後代類中,我們創建了一個與父類中的方法同名的方法。
  2. 我們告訴編譯器我們不只是給方法一個與父類中相同的名稱,而是我們想要覆蓋它的行為。這個給編譯器的“消息”是通過@Override註釋傳達的。
    方法上方的 @Override 註釋告訴編譯器(以及其他閱讀您的代碼的程序員),“別擔心。這不是錯誤或疏忽。我知道這個方法已經存在,我想覆蓋它.

  3. 我們為每個後代類編寫了我們需要的實現。調用該方法時speak(),蛇應該發出嘶嘶聲,熊應該咆哮,等等。
讓我們看看它在程序中是如何工作的:
public class Main {

   public static void main(String[] args) {

       Animal animal1 = new Dog();
       Animal animal2 = new Cat();
       Animal animal3 = new Bear();
       Animal animal4 = new Snake();

       animal1.speak();
       animal2.speak();
       animal3.speak();
       animal4.speak();
   }
}
控制台輸出

Woof! 
Meow! 
Growl! 
Hiss!
太好了,一切正常!我們創建了 4 個類型為父Animal類的引用變量,並為它們分配了 4 個不同的子類對象。因此,每個對象的行為都不同。對於每個派生類,覆蓋的speak()方法替換類speak()的現有方法Animal(它只在控制台上顯示“Speaking:”)。方法重載的工作原理 - 3方法覆蓋有幾個限制:
  1. 重寫的方法必須與父類中的方法具有相同的參數。

    如果speak父類的方法以aString為輸入,那麼子類中重寫的方法也必須以aString為輸入。否則,編譯器會產生一個錯誤:

    public class Animal {
    
       public void speak(String s) {
    
           System.out.println("Speaking: " + s);
       }
    }
    
    public class Cat extends Animal {
    
       @Override // Error!
       public void speak() {
           System.out.println("Meow!");
       }
    }

  2. 重寫的方法必須與父類中的方法具有相同的返回類型。

    否則,我們會得到一個編譯錯誤:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    
    public class Cat extends Animal {
    
       @Override
       public String speak() {         // Error!
           System.out.println("Meow!");
           return "Meow!";
       }
    }

  3. 重寫方法的訪問修飾符也不能與原始方法不同:

    public class Animal {
    
       public void speak() {
    
           System.out.println("Hello!");
       }
    }
    
    public class Cat extends Animal {
    
       @Override
       private void speak() {      // Error!
           System.out.println("Meow!");
       }
    }
在 Java 中,方法覆蓋是實現多態性的一種方式。這意味著它的主要優勢是我們之前談到的靈活性。我們可以構建一個簡單且合乎邏輯的類層次結構,每個類都有特定的行為(吠叫的狗,喵喵叫的貓),但只有一個接口——speak()每個人都有一個方法,而不是一堆不同的方法,例如bark(),meow()等等。