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版本始终会被调用。
- 调用哪个存在隐藏关系的
staticmethod版本则取决于是从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中的
defaultmethod。
考虑下面的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编译器会报错。 […]