重写和隐藏方法 实例方法
子类中的实例方法的签名(名称,加上其参数的数量和类型)和返回类型与超类中的实例方法相同,将覆盖超类的方法。
子类覆盖方法的能力允许类从行为“足够接近”的超类继承,然后根据需要修改行为,重写方法与它重写的方法具有相同的名称、数量和参数类型,以及返回类型。重写方法还可以返回由被重写方法返回的类型的子类型,此子类型称为协变返回类型。
覆盖方法时,你可能希望使用@Override注解来指示编译器你要覆盖超类中的方法,如果由于某种原因,编译器检测到该方法在其中一个超类中不存在,那么它将生成错误,有关@Override的更多信息,请参阅注解。
静态方法如果子类定义的静态方法与超类中的静态方法具有相同的签名,则子类中的方法会隐藏超类中的方法。
隐藏静态方法和覆盖实例方法之间的区别具有重要意义:
被调用的重写的实例方法的版本是子类中的版本。
被调用的隐藏静态方法的版本取决于它是从超类还是从子类调用的。
考虑一个包含两个类的示例,第一个是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编译器遵循继承规则来解决名称冲突,这些规则由以下两个原则驱动:
实例方法优先于接口默认方法。
考虑以下类和接口:
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。
如果尝试将超类中的实例方法更改为子类中的静态方法,则会出现编译时错误,反之亦然。
总结下表总结了在定义具有与超类中的方法相同的签名的方法时发生的情况。
超类实例方法 | 超类静态方法 | |
---|---|---|
子类实例方法 | 覆盖 | 生成编译时错误 |
子类静态方法 | 生成编译时错误 | 隐藏 |
注意:在子类中,你可以重载从超类继承的方法,这样的重载方法既不隐藏也不覆盖超类实例方法 — 它们是新方法,对于子类是唯一的。上一篇:继承 下一篇:多态性
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/72877.html
继承 在前面的课程中,你已经多次看到了继承,在Java语言中,类可以从其他类派生,从而从这些类继承字段和方法。 定义:从另一个类派生的类称为子类(也是派生类,扩展类或子类),派生子类的类称为超类(也是基类或父类)。 除了Object没有超类,每个类都有一个且只有一个直接超类(单继承),在没有任何其他显式超类的情况下,每个类都隐式地是Object的子类。 类可以从派生自类的类派生的类派生,依此类推,...
使用super关键字 访问超类成员 如果你的方法覆盖了它的一个超类的方法,你可以通过使用关键字super来调用被重写的方法,你也可以使用super来引用隐藏字段(尽管不鼓励隐藏字段),虑这个类,Superclass: public class Superclass { public void printMethod() { System.out.println(Print...
多态性 多态性的字典定义是指生物学中的原理,其中生物体或物种可以具有许多不同的形式或阶段,这个原则也可以应用于面向对象的编程和像Java语言之类的语言,类的子类可以定义它们自己的唯一行为,但仍然共享父类的一些相同功能。 可以通过对Bicycle类的微小修改来演示多态性,例如,可以将printDescription方法添加到显示当前存储在实例中的所有数据的类中。 public void printD...
Java™ 教程 Java教程是为JDK 8编写的,本页面中描述的示例和实践没有利用在后续版本中引入的改进。 Java教程是希望使用Java编程语言创建应用程序的程序员的实用指南,其中包括数百个完整的工作示例和数十个课程,相关课程组被组织成教程。 覆盖基础知识的路径 这些教程以书籍的形式提供,如Java教程,第六版,前往Amazon.com购买。 入门 介绍Java技术和安装Java开发软件并使用...
摘要:抽象数据类型的多个不同表示可以共存于同一个程序中,作为实现接口的不同类。封装和信息隐藏信息隐藏将精心设计的模块与不好的模块区分开来的唯一最重要的因素是其隐藏内部数据和其他模块的其他实施细节的程度。 大纲 面向对象的标准基本概念:对象,类,属性,方法和接口OOP的独特功能 封装和信息隐藏 继承和重写 多态性,子类型和重载 静态与动态分派 Java中一些重要的Object方法设计好的类面向...
阅读 3728·2021-08-30 09:47
阅读 3582·2019-08-30 15:56
阅读 645·2019-08-30 14:18
阅读 661·2019-08-29 16:17
阅读 2034·2019-08-29 11:07
阅读 617·2019-08-26 13:53
阅读 3409·2019-08-26 10:26
阅读 2448·2019-08-23 18:30