MST
星途 面试题库

面试题:Java多态中过度重写问题及策略

请举例说明在Java多态中,可能出现过度重写的场景,并阐述至少两种避免过度重写的策略。
21.3万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

过度重写场景举例

假设我们有一个鸟类的父类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方法就属于过度重写,因为企鹅本质上不具备飞行能力,却在继承结构中重写了飞行方法。

避免过度重写的策略

  1. 使用final方法
    • 如果在父类Bird中,将fly方法声明为final,子类就无法重写该方法。
    class Bird {
        public final void fly() {
            System.out.println("Bird is flying");
        }
    }
    class Penguin extends Bird {
        // 这里如果尝试重写fly方法,会编译报错
    }
    
  2. 设计更合理的继承结构
    • 可以重新设计继承结构,例如创建一个接口Flyable,让具有飞行能力的鸟类实现这个接口,而企鹅不实现。
    interface Flyable {
        void fly();
    }
    class Sparrow implements Flyable {
        @Override
        public void fly() {
            System.out.println("Sparrow is flying");
        }
    }
    class Penguin {
        // 企鹅类不实现Flyable接口,也就不会出现错误重写飞行方法的问题
    }
    
  3. 使用模板方法模式并结合钩子方法
    • 在父类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方法。