Java 中如何正确调用父类中被重写的函数

在 java 中,`this.

print()` 总是动态绑定到运行时对象的实际类型(即子类重写后的方法),无法像 c++ 那样通过 `a::print()` 显式调用父类版本;若需调用父类方法,必须使用 `super.print()`,且需避免 `super` 调用链中意外触发子类重写方法导致的无限递归。

你遇到的 StackOverflowError 根源在于 Java 的动态绑定(运行时多态)机制与 C++ 的静态作用域解析存在本质差异。在你的 Java 示例中:

class B extends A {
    @Override
    public void print() {
        super.doPrint(); // ← 问题在此!
    }
}

super.doPrint() 会执行父类 A.doPrint(),而该方法内部调用的是 this.print() —— 注意:此时 this 仍是 B 类型的实例,因此 this.print() 依然会分派到 B.print(),从而形成 B.print() → A.doPrint() → B.print() → ... 的死循环。

✅ 正确做法是:若想在子类中显式复用父类逻辑,应直接调用 super.print()(而非 super.doPrint()),并确保调用路径不重新落入子类重写方法。

以下是修复后的可运行示例:

class A {
    public void doPrint() {
        this.print(); // 动态绑定:对 A 实例调用 A.print(),对 B 实例调用 B.print()
    }

    public void print() {
        System.out.println("This is A");
    }
}

class B extends A {
    @Override
    public void doPrint() {
        // 方案1:想先执行父类 print,再扩展逻辑 → 直接 super.print()
        super.print();
        System.out.println("Additional behavior in B");

        // 方案2:若仍需封装在 doPrint 中,可定义新方法避免歧义
        // doParentPrint(); // 自定义非虚方法(见下方)
    }

    @Override
    public void print() {
        // ✅ 安全:显式调用父类 print,不会再次触发重写
        super.print();
        System.out.println("This is B (extended)");
    }

    // ? 可选:为避免混淆,将父类核心逻辑提取为 final 方法(不可重写)
    public final void doParentPrint() {
        print(); // ← 这里仍会动态绑定!注意:若 print 被重写,此行仍调用子类版本
    }

    // ✅ 更稳健:将父类行为封装为 private/final 方法,彻底规避多态
    public void doPrintSafe() {
        printImpl(); // 调用私有实现,保证是 A 的逻辑
    }

    private void printImpl() {
        System.out.println("This is A (private impl)");
    }
}

public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.doPrint();     // 输出:This is B (extended)
        // b.print();    // 同上(因重写)
        // b.doPrintSafe(); // 输出:This is A (private impl)
    }
}

? 关键注意事项:

  • super.methodName() 是 Java 中唯一合法且安全的显式调用父类被重写方法的方式;
  • this.methodName() 和未加限定的 methodName() 完全等价,永远遵循运行时类型,绝不会“退回到”当前类声明的版本;
  • 不要让 super.xxx() 的调用链间接绕回子类重写方法(如 super.doPrint() → this.print() → 子类重写),这是递归陷阱的常见根源;
  • 若需稳定复用父类逻辑,推荐将核心行为封装为 private 或 final 方法,从设计上切断多态干扰。

总结:Java 不支持 C++ 式的 A::print() 语法,但通过 super.print() + 清晰的职责分离(如提取私有实现、避免交叉调用),完全可以安全、可维护地实现相同意图。