Java™ 教程(重寫和隱藏方法)

重寫和隱藏方法

實例方法

子類中的實例方法的簽名(名稱,加上其參數的數量和類型)和返回類型與超類中的實例方法相同,將覆蓋超類的方法。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的一個子類,叫作Catget

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編譯器會產生編譯器錯誤,你必須顯式覆蓋超類型方法。

考慮一下如今能夠飛行的計算機控制汽車的例子,你有兩個接口(OperateCarFlyCar)爲同一方法提供默認實現(startEngine):

public interface OperateCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}
public interface FlyCar {
    // ...
    default public int startEngine(EncryptedKey key) {
        // Implementation
    }
}

實現OperateCarFlyCar的類必須覆蓋方法startEngine,你可使用super關鍵字調用任何默認實現。

public class FlyingCar implements OperateCar, FlyCar {
    // ...
    public int startEngine(EncryptedKey key) {
        FlyCar.super.startEngine(key);
        OperateCar.super.startEngine(key);
    }
}

super以前的名稱(在此示例中爲FlyCarOperateCar)必須引用定義或繼承默認調用方法的直接超接口,這種形式的方法調用不限於區分包含具備相同簽名的默認方法的多個已實現接口,你可使用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 horseMustang類繼承了Horse類中的方法identifyMyself,它覆蓋了Mammal接口中同名的抽象方法。

注意:接口中的靜態方法永遠不會被繼承。

修飾符

重寫方法的修飾符能夠容許比被重寫方法更多但不是更少的訪問,例如,超類中的protected實例方法能夠在子類中是public,但不能是private

若是嘗試將超類中的實例方法更改成子類中的靜態方法,則會出現編譯時錯誤,反之亦然。

總結

下表總結了在定義具備與超類中的方法相同的簽名的方法時發生的狀況。

超類實例方法 超類靜態方法
子類實例方法 覆蓋 生成編譯時錯誤
子類靜態方法 生成編譯時錯誤 隱藏
注意:在子類中,你能夠重載從超類繼承的方法,這樣的重載方法既不隱藏也不覆蓋超類實例方法 — 它們是新方法,對於子類是惟一的。

上一篇:繼承

下一篇:多態性

相關文章
相關標籤/搜索