面试题答案
一键面试过度重写场景举例
假设我们有一个鸟类的父类Bird
,其中有一个fly
方法:
class Bird {
public void fly() {
System.out.println("Bird is flying");
}
}
然后有一个子类Penguin
继承自Bird
,企鹅实际上不会飞,但由于继承了Bird
类,可能会错误地重写fly
方法:
class Penguin extends Bird {
@Override
public void fly() {
System.out.println("Penguin can't fly, but this method is wrongly overridden");
}
}
这里Penguin
重写fly
方法就属于过度重写,因为企鹅本质上不具备飞行能力,却在继承结构中重写了飞行方法。
避免过度重写的策略
- 使用
final
方法:- 如果在父类
Bird
中,将fly
方法声明为final
,子类就无法重写该方法。
class Bird { public final void fly() { System.out.println("Bird is flying"); } } class Penguin extends Bird { // 这里如果尝试重写fly方法,会编译报错 }
- 如果在父类
- 设计更合理的继承结构:
- 可以重新设计继承结构,例如创建一个接口
Flyable
,让具有飞行能力的鸟类实现这个接口,而企鹅不实现。
interface Flyable { void fly(); } class Sparrow implements Flyable { @Override public void fly() { System.out.println("Sparrow is flying"); } } class Penguin { // 企鹅类不实现Flyable接口,也就不会出现错误重写飞行方法的问题 }
- 可以重新设计继承结构,例如创建一个接口
- 使用模板方法模式并结合钩子方法:
- 在父类
Bird
中定义一个模板方法,并且包含一个钩子方法来决定是否执行具体的飞行逻辑。
class Bird { public void performFly() { if (canFly()) { fly(); } else { System.out.println("This bird can't fly"); } } protected void fly() { System.out.println("Bird is flying"); } protected boolean canFly() { return true; } } class Penguin extends Bird { @Override protected boolean canFly() { return false; } }
- 这样,
Penguin
子类通过重写钩子方法canFly
来控制是否执行飞行逻辑,而不是错误地重写fly
方法。
- 在父类