子類中的實例方法的簽名(名稱,加上其參數的數量和類型)和返回類型與超類中的實例方法相同,將覆蓋超類的方法。segmentfault
子類覆蓋方法的能力容許類從行爲「足夠接近」的超類繼承,而後根據須要修改行爲,重寫方法與它重寫的方法具備相同的名稱、數量和參數類型,以及返回類型。重寫方法還能夠返回由被重寫方法返回的類型的子類型,此子類型稱爲協變返回類型。ide
覆蓋方法時,你可能但願使用@Override
註解來指示編譯器你要覆蓋超類中的方法,若是因爲某種緣由,編譯器檢測到該方法在其中一個超類中不存在,那麼它將生成錯誤,有關@Override
的更多信息,請參閱註解。code
若是子類定義的靜態方法與超類中的靜態方法具備相同的簽名,則子類中的方法會隱藏超類中的方法。繼承
隱藏靜態方法和覆蓋實例方法之間的區別具備重要意義:接口
考慮一個包含兩個類的示例,第一個是Animal
,它包含一個實例方法和一個靜態方法:字符串
public class Animal { public static void testClassMethod() { System.out.println("The static method in Animal"); } public void testInstanceMethod() { System.out.println("The instance method in Animal"); } }
第二個類是Animal
的一個子類,叫作Cat
:get
public class Cat extends Animal { public static void testClassMethod() { System.out.println("The static method in Cat"); } public void testInstanceMethod() { System.out.println("The instance method in Cat"); } public static void main(String[] args) { Cat myCat = new Cat(); Animal myAnimal = myCat; Animal.testClassMethod(); myAnimal.testInstanceMethod(); } }
Cat
類重寫Animal
中的實例方法,並隱藏Animal
中的靜態方法,此類中的main
方法建立Cat
的實例,並在類上調用testClassMethod()
並在實例上調用testInstanceMethod()
。編譯器
該程序的輸出以下:io
The static method in Animal The instance method in Cat
正如所承諾的那樣,被調用的隱藏靜態方法的版本是超類中的版本,被調用的重寫實例方法的版本是子類中的版本。編譯
接口中的默認方法和抽象方法與實例方法同樣是繼承的,可是,當類或接口的超類型提供具備相同簽名的多個默認方法時,Java編譯器遵循繼承規則來解決名稱衝突,這些規則由如下兩個原則驅動:
考慮如下類和接口:
public class Horse { public String identifyMyself() { return "I am a horse."; } } public interface Flyer { default public String identifyMyself() { return "I am able to fly."; } } public interface Mythical { default public String identifyMyself() { return "I am a mythical creature."; } } public class Pegasus extends Horse implements Flyer, Mythical { public static void main(String... args) { Pegasus myApp = new Pegasus(); System.out.println(myApp.identifyMyself()); } }
方法Pegasus.identifyMyself
返回字符串I am a horse
。
考慮如下接口和類:
public interface Animal { default public String identifyMyself() { return "I am an animal."; } } public interface EggLayer extends Animal { default public String identifyMyself() { return "I am able to lay eggs."; } } public interface FireBreather extends Animal { } public class Dragon implements EggLayer, FireBreather { public static void main (String... args) { Dragon myApp = new Dragon(); System.out.println(myApp.identifyMyself()); } }
方法Dragon.identifyMyself
返回字符串I am able to lay eggs
。
若是兩個或多個獨立定義的默認方法衝突,或者默認方法與抽象方法衝突,則Java編譯器會產生編譯器錯誤,你必須顯式覆蓋超類型方法。
考慮一下如今能夠飛行的計算機控制汽車的例子,你有兩個接口(OperateCar
和FlyCar
)爲同一方法提供默認實現(startEngine
):
public interface OperateCar { // ... default public int startEngine(EncryptedKey key) { // Implementation } } public interface FlyCar { // ... default public int startEngine(EncryptedKey key) { // Implementation } }
實現OperateCar
和FlyCar
的類必須覆蓋方法startEngine
,你可使用super
關鍵字調用任何默認實現。
public class FlyingCar implements OperateCar, FlyCar { // ... public int startEngine(EncryptedKey key) { FlyCar.super.startEngine(key); OperateCar.super.startEngine(key); } }
super
以前的名稱(在此示例中爲FlyCar
或OperateCar
)必須引用定義或繼承默認調用方法的直接超接口,這種形式的方法調用不限於區分包含具備相同簽名的默認方法的多個已實現接口,你可使用super
關鍵字在類和接口中調用默認方法。
類中的繼承實例方法能夠覆蓋抽象接口方法,考慮如下接口和類:
public interface Mammal { String identifyMyself(); } public class Horse { public String identifyMyself() { return "I am a horse."; } } public class Mustang extends Horse implements Mammal { public static void main(String... args) { Mustang myApp = new Mustang(); System.out.println(myApp.identifyMyself()); } }
方法Mustang.identifyMyself
返回字符串I am a horse
,Mustang
類繼承了Horse
類中的方法identifyMyself
,它覆蓋了Mammal
接口中同名的抽象方法。
注意:接口中的靜態方法永遠不會被繼承。
重寫方法的修飾符能夠容許比被重寫方法更多但不是更少的訪問,例如,超類中的protected
實例方法能夠在子類中是public
,但不能是private
。
若是嘗試將超類中的實例方法更改成子類中的靜態方法,則會出現編譯時錯誤,反之亦然。
下表總結了在定義具備與超類中的方法相同的簽名的方法時發生的狀況。
超類實例方法 | 超類靜態方法 | |
---|---|---|
子類實例方法 | 覆蓋 | 生成編譯時錯誤 |
子類靜態方法 | 生成編譯時錯誤 | 隱藏 |
注意:在子類中,你能夠重載從超類繼承的方法,這樣的重載方法既不隱藏也不覆蓋超類實例方法 — 它們是新方法,對於子類是惟一的。