文档

Java™ 教程-Java Tutorials 中文版
覆盖和隐藏方法
Trail: Learning the Java Language
Lesson: Interfaces and Inheritance
Section: Inheritance

覆盖和隐藏方法

实例方法

具有相同签名(名称,加上其参数的数量和类型)和返回值的子类中的实例方法 overrides (覆盖) 超类的方法。

子类覆盖方法的能力允许类从行为 "足够接近" 的超类继承,然后根据需要修改行为。覆盖方法与它覆盖的方法具有相同的名称,参数的数量和类型,和返回类型。覆盖方法还可以返回由覆盖方法返回的类型的子类型。此子类型称为 covariant return type (协变返回类型)

覆盖方法时,你可能希望使用 @Override 注解来指示编译器你要覆盖超类中的方法。如果由于某种原因,编译器检测到该方法在其中一个超类中不存在,那么它将生成错误。有关 @Override 的详细信息,请参阅 Annotations

静态方法

如果子类定义的静态方法与超类中的静态方法具有相同的签名,则子类方法 hides (隐藏) 超类中的方法。

隐藏静态方法和覆盖实例方法之间有显著区别:

考虑一个包含两个类的示例。第一个是 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

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() 方法。

该程序的输出如下:

The static method in Animal
The instance method in Cat

正如所承诺的那样,被调用的隐藏静态方法的版本是超类中的版本,被调用的重写实例方法的版本是子类中的版本。

接口方法

默认方法抽象方法 与实例方法一样是继承的。但是,当类或接口的超类型提供具有相同签名的多个默认方法时,Java 编译器将遵循继承规则来解决名称冲突。这些规则由以下两个原则驱动:

如果两个或多个独立定义的默认方法冲突,或者默认方法与抽象方法冲突,则 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 horse.Mustang 继承了方法 identifyMyselfHorse 类,它会覆盖接口 Mammal 中的同名抽象方法。

注意:接口中的静态方法永远不会被继承。

修饰符

覆盖方法的访问说明符可以允许比覆盖方法更多,但不能更少,的访问。例如,超类中的 protected 实例方法可以在子类中 public,但不能 private。

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

总结

下表 总结了在定义与超类中的方法具有相同签名的方法时会发生什么。

定义与超类的方法具有相同签名的方法
  超类实例方法 超类静态方法
子类实例方法 Overrides 生成编译时错误
子类静态方法 生成编译时错误 Hides

注意: 在子类中,你可以重载从超类继承的方法。这样的重载方法既不隐藏也不覆盖超类实例方法 - 它们是新方法,对于子类是唯一的。

Previous page: Multiple Inheritance of State, Implementation, and Type
Next page: Polymorphism