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

若是尝试将超类中的实例方法更改成子类中的静态方法,则会出现编译时错误,反之亦然。

总结

下表总结了在定义具备与超类中的方法相同的签名的方法时发生的状况。

超类实例方法 超类静态方法
子类实例方法 覆盖 生成编译时错误
子类静态方法 生成编译时错误 隐藏
注意:在子类中,你能够重载从超类继承的方法,这样的重载方法既不隐藏也不覆盖超类实例方法 — 它们是新方法,对于子类是惟一的。

上一篇:继承

下一篇:多态性

相关文章
相关标签/搜索