Method的重写(override)与隐藏(hide)
Instance Method
child class中的instance method如果和parent class的某一instance method有一致的签名(signature)和返回类型,则会重写parent class的该method。
重写的能力有助于child class继承行为类似的parent class,在此基础上继续按需求定制特定method的行为。重写的method与parent class中的method有一致的名字、参数类型/数目和返回类型。重写的方法也可以返回parent class中method返回类型的child,这称为协变返回类型(covariant return type)。
当重写方法时,你可以使用@Override
注释来提示编译器该method重写了parent class的method。这样一旦编译器发现parent class中没有对应的method就会报错。
Static Method
如果child class定义了与parent class中某一static
method签名一致的static
method,该方法则会隐藏parent class的static
method。
重写instance method和隐藏static
method有重要的区别:
- 重写的instance method版本始终会被调用。
- 调用哪个存在隐藏关系的
static
method版本则取决于是从child class还是parent class调用。
考虑以下这两个class。第一个名为Animal
,有一个instance method和一个static
method:
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
的child class:
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
的instance method并隐藏了static
method。main
method中创建了Cat
的一个object并调用parent class的testClassMethod()
及类型转换为parent的object的testInstanceMethod()
。
程序的输出如下:
The static method in Animal
The instance method in Cat
与我们的预期一致,被隐藏的method当从parent class调用时可以回到之前的版本,而被重写的method则始终是child object的版本。
Interface Method
default
method和abstract
method与instance method一样继承。然而当interface提供多个签名一致的default
method时,Java编译器按照如下的两个原则解决命名冲突。
- instance method的优先级高于interface中的
default
method。
考虑下面的class和interface:
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()); } }
method Pegasus.identifyMyself
将返回I am a horse
。
- 已经被重写的method会被忽略。这当多个interface拥有共同祖先时会发生。
考虑下面的interface和class:
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()); } }
method Dragon.identifyMyself
将返回I am able to lay eggs
。
当两个或以上独立定义的default
method冲突,或default
method与abstract
method冲突时,Java编译器会报错。你必须显式重写所实现的interface中的这些method。
考虑下面电脑控制的飞行汽车示例。两个interface(OperateCar
与FlyCar
)对同一startEngine
method提供了默认实现。
public interface OperateCar { // ... default public int startEngine(EncryptedKey key) { // Implementation } } public interface FlyCar { // ... default public int startEngine(EncryptedKey key) { // Implementation } }
同时实现OperateCar
与FlyCar
的class FlyingCar
就必须重写startEngine
method。可以使用super
关键字调用任一interface中的默认实现。
public class FlyingCar implements OperateCar, FlyCar { // ... public int startEngine(EncryptedKey key) { FlyCar.super.startEngine(key); OperateCar.super.startEngine(key); } }
super
前的名字(在例子中即为OperateCar
与FlyCar
)必须是所实现的interface之一,这个interface定义或继承了所调用的method。这种对于default
method的调用方式并不局限于interface,也适用于class。
从parent class继承而来的instance method会重写interface的abstract
method。考虑下面的interface和class:
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()); } }
method Mustang.identifyMyself
将返回I am a horse
。class Mustang
从class Horse
继承了method identifyMyself
,其重写了interface Mammal
中的同名abstract
method。
访问权限
重写的method可以比parent class中对应method有更多的访问权限,但不能更少。例如protected
method可被重写为public
,但不能为private
。
不能在child class中变更method的static
状态,否则在编译时会报错。
总结
下表概括了child class所定义的method与parent class中method签名相同时的各种情况。
parent instance method | parent static method |
|
---|---|---|
child instance method | 重写 | 编译错误 |
child static method |
编译错误 | 隐藏 |
1 条评论
单人纸牌(Elevens Lab)活动1:设计并创建class Card – AP Computer Science · 2018年5月12日 下午3:16
[…] 阅读目录里已经部分完成的class Card框架。在读的时候,你会注意到在toString method上使用的@Override注释。Java中,@Override注释被用来表明某个method一定重写了parent class中的同名method。在这个例子中,class Object(Java所有class默认的parent class)的toString method要被class Card的对应method重写。如果该method并没有实际重写parent class的对应method,Java编译器会报错。 […]