
在 Java 中,即使父类方法内部直接调用 this.method1(int),只要该方法被子类重写且实际对象是子类实例,JVM 仍会在运行时动态绑定到子类版本——这是运行时多态的核心机制。
在 java 中,即使父类方法内部直接调用 `this.method1(int)`,只要该方法被子类重写且实际对象是子类实例,jvm 仍会在运行时动态绑定到子类版本——这是运行时多态的核心机制。
你遇到的现象并非 Bug,而是 Java 运行时多态(Runtime Polymorphism)的预期行为。关键在于:方法调用的解析发生在运行时,依据的是对象的实际类型(new B()),而非当前代码所在的类或引用类型。
让我们逐步还原你的调用链:
B b = new B();
b.method1("HI"); // 实际类型是 B → 调用 B.method1(String)→ 进入 B.method1(String):
@Override
public void method1(String arg) {
super.method1(arg); // 显式委托给 A 的 String 版本
}→ 进入 A.method1(String):
立即学习“Java免费学习笔记(深入)”;
public void method1(String arg) {
this.method1(1); // 注意:this 指向的是当前对象,即 new B() 实例!
}⚠️ 此处是理解的关键:this 始终指向运行时的真实对象(B 实例),因此 this.method1(1) 触发的是 动态分派(dynamic dispatch) —— JVM 查看 this 的实际类型为 B,发现 B 重写了 method1(int),于是调用 B.method1(int),输出 "I'm B class"。
这与“静态分派”(如重载解析)不同:method1(int) 的签名在编译期已确定,但具体执行哪个实现,由运行时对象类型决定。
✅ 解决方案(按场景选择)
| 目标 | 方法 | 示例 |
|---|---|---|
| 强制调用父类实现(绕过多态) | 使用 super.method1(1) 明确指定 |
在 A.method1(String) 中改为 super.method1(1)
|
| 禁止子类覆盖(设计意图明确) | 将父类方法声明为 final
|
public final void method1(int arg) |
| 避免意外重写(推荐设计) | 将 method1(int) 设为 private 或包私有(但需注意:private 方法不可被重写,自然规避问题) |
private void method1(int arg) |
? 补充说明:
private、static、final方法不参与动态绑定,它们在编译期就完成静态绑定(early binding)。而this.method1(int)是虚方法调用(virtual call),必然走运行时查找。
? 最佳实践建议
- 若父类中某方法逻辑必须保证自身实现不被替换,请用
final修饰; - 若子类重写是为了扩展行为,但父类内部调用需保持一致性,应显式使用
super.; - 避免在父类方法中依赖“未被重写的假设”,多态是 Java 的基石,应主动设计以兼容它,而非规避它。
通过理解 this 的动态语义和 JVM 的方法分派机制,你就能精准控制继承体系中的行为流向。


















