你好!您已經在使用 Java 方法並且對它們了解很多。您可能遇到過這樣的情況,一個類有許多名稱相同但參數不同的方法。您會記得在那些情況下我們使用了方法重載。今天我們考慮另一種情況。想像一下,我們有一個共享方法,但它必須在不同的類中做不同的事情。我們如何實現這種行為?為了便於理解,讓我們考慮一個代表動物的Animal父類,我們將在其中 創建一個speak方法:
我們的目標很簡單:避免創建大量的說話方法。我們不想創建用於喵喵叫的catSpeak()方法、用於發出嘶嘶聲的snakeSpeak()方法等,而是調用speak()方法,讓蛇發出嘶嘶聲、貓叫聲和狗叫聲。我們可以使用方法覆蓋輕鬆實現這一點。維基百科對術語“覆蓋”給出了以下解釋:方法覆蓋,在面向對象編程中,是一種語言特性,它允許子類或子類提供其超類之一已經提供的方法的特定實現或父類 這基本上是正確的。方法覆蓋讓你可以使用父類的一些方法並在每個子類中編寫你自己的實現。新實現“替換”了父類在子類中的實現。讓我們看看這在示例中的樣子。創建 4 個繼承我們的Animal類的類:
public class Animal {
public void speak() {
System.out.println("Hello!");
}
}
雖然我們才剛剛開始編寫程序,但您可能會看到一個潛在的問題:世界上有很多動物,它們“說話”的方式都不一樣:貓喵喵叫、鴨子嘎嘎叫、蛇嘶嘶叫。 
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,然後在菜單中選擇“覆蓋方法...”。習慣使用熱鍵從一開始——它會幫助你更快地編寫程序!為了指定我們需要的行為,我們做了一些事情:
- 在每個子類中,我們創建了一個與父類方法同名的方法。
- 我們告訴編譯器,將方法命名為與父類中相同的名稱並非偶然:我們想要覆蓋它的行為。為了將此信息傳達給編譯器,我們在方法上方設置了@Override 註釋。
當放在方法上方時,@Override 註釋會通知編譯器(以及閱讀您的代碼的程序員):'一切正常。這不是錯誤。我不是健忘。我知道這樣的方法已經存在,我想覆蓋它'。 - 我們為每個子類編寫了我們需要的實現。當調用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()方法替換了Animal類中的“本地” speak()方法(它只顯示“Hello!”)。 覆蓋有幾個限制: 
-
重寫的方法必須具有與父方法相同的參數。
如果父類的speak方法有一個String參數,那麼子類中被重寫的方法也必須有一個String參數。否則,編譯器會產生一個錯誤:
public class Animal { public void speak(String s) { System.out.println("Hello! " + s); } } public class Cat extends Animal { @Override // Error! public void speak() { System.out.println("Meow!"); } }
-
重寫的方法必須與父方法具有相同的返回類型。
否則,我們會得到一個編譯器錯誤:
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!"; } }
-
重寫方法的訪問修飾符也必須與“原始”方法相同:
public class Animal { public void speak() { System.out.println("Hello!"); } } public class Cat extends Animal { @Override private void speak() { // Error! System.out.println("Meow!"); } }
GO TO FULL VERSION