Java中正确调用父类被重写方法的实践指南

在java中,`super.methodname()`用于显式调用父类的被重写方法;而`this.methodname()`或无修饰的`methodname()`始终触发运行时实际对象类型的重写版本,无法绕过动态绑定——这是避免无限递归和实现精确方法调度的关键。

你遇到的 StackOverflowError 根源在于 Java 的动态方法分派(dynamic dispatch)机制:当 B 实例调用 doPrint() 时,由于 B 重写了 print(),this.print()(等价于 print())永远解析为 B.print(),而非 A.print()。而 B.print() 又调用 super.doPrint(),后者再次调用 this.print() —— 形成闭环。

✅ 正确做法是:在子类中使用 super.print() 直接调用父类的 print() 实现,而非通过 super.doPrint() 间接跳转。以下是修正后的可运行代码:

class A {
    public void doPrint() {
        this.print(); // 调用当前对象的 print()(多态)
    }

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

class B extends A {
    @Override
    public void doPrint() {
        // ✅ 正确:直接委托给父类的 print()
        super.print();
        // 或者:System.out.println("Custom prefix from B"); super.print();
    }

    // ❌ 移除重写的 print() 方法,避免循环依赖
    // 若必须重写 print(),则需明确区分用途(见下方说明)
}

public class Main {
    public static void main(String[] args) {
        B b = new B();
        b.doPrint(); // 输出: "This is A"
    }
}

⚠️ 关键注意事项:

  • super.print() 是唯一安全调用父类具体实现的方式,它绕过动态绑定,强制执行父类版本;
  • super.doPrint() 仍会触发 this.print() 的动态绑定,因此不能用于“跳过子类重写”;
  • 若业务逻辑确实需要 B.print() 存在(例如提供增强版打印),则 B.print() 内部应显式调用 super.print(),而非 super.doPrint():
@Override
public void print() {
    System.out.pri

nt("[B] "); super.print(); // ✅ 安全:直接复用 A 的 print 实现 }

? 总结:Java 不支持 C++ 风格的 A::print() 语法,但 super.method() 提供了同等语义的、类型安全的父类方法调用能力。设计时应遵循“子类重写方法只负责自身逻辑扩展,父类基础行为统一由 super. 显式调用”,即可彻底规避递归陷阱并保持代码清晰性。