
本文深入剖析java中继承方法的执行行为,重点解释被继承方法在运行时如何访问子类字段、调用子类重写方法,以及为何仍遵循父类的可见性约束——核心在于动态绑定(dynamic binding)与静态/动态类型分离。
本文深入剖析java中继承方法的执行行为,重点解释被继承方法在运行时如何访问子类字段、调用子类重写方法,以及为何仍遵循父类的可见性约束——核心在于动态绑定(dynamic binding)与静态/动态类型分离。
在Java面向对象编程中,继承不仅是代码复用的手段,更承载着一套精密的运行时行为规则。一个常被误解的关键点是:当子类对象调用从父类继承而来的非私有方法时,该方法内部访问的字段和调用的其他方法,究竟属于哪个类? 答案并非由方法定义处(父类)决定,而是由运行时实际对象的类型(即动态类型) 动态确定——这正是Java多态性的基石。
一、字段访问:取决于声明位置,而非动态类型(注意隐藏!)
需特别注意:字段(field)不参与动态绑定。若子类声明了与父类同名的字段(如示例中 class B 声明了 private int m;),则该字段会隐藏(hide) 父类的同名字段,而非覆盖(override)。此时:
- b.methodOne(6) 执行时,methodOne 是父类 A 中定义的方法;
- 其内部语句 m -= i; 访问的是 A 类中定义的 private int m(因为 methodOne 的字节码指令明确指向 A.m);
- 而 B 类中自己的 private int m 完全不可见于 methodOne 内部,二者是独立存储的两个变量。
✅ 正确理解:
// 在 A.methodOne 中: m -= i; // 操作的是 A 类的 m(即 super.m),值为 4(由 super(n) 初始化) increase(i); // 此处才发生动态绑定!调用的是 B.increase(因 b 是 B 实例)
⚠️ 关键误区警示:
不要误认为 b.m(子类字段)会被 methodOne 直接使用——这是字段隐藏导致的认知陷阱。若需统一操作,应避免在子类中重命名父类字段,或通过受保护的getter/setter封装访问。
二、方法调用:严格遵循动态绑定(Runtime Polymorphism)
Java中非private、非static、非final的实例方法调用,全部基于动态类型解析。这意味着:
立即学习“Java免费学习笔记(深入)”;
- b.methodOne(6) 中,虽然 b 的静态类型(compile-time type)是 A,但 JVM 在运行时发现 b 实际指向 B 类实例;
- 因此,当 methodOne 内部执行 increase(i) 时,JVM 查找 B 类是否重写了 increase —— 发现存在,于是调用 B.increase(i);
- 若 B 未重写 increase,则自动回退至 A.increase(i)。
这就是多态的核心体现:“谁的对象,就调用谁的方法”。
三、可见性(Access Control):由方法定义处的类决定
继承方法的访问权限检查发生在编译期,依据的是方法声明所在的类(即父类)的可见性规则:
- visibilityTest() 是 A 类中的 public 方法,因此可通过任何 A 类型引用(包括 A b = new B())合法调用;
- 方法体内对 private int n 的访问(n++)之所以成功,是因为该代码位于 A 类内部——访问私有成员的权限,取决于当前代码所在类,而非调用者类型;
- 即使 b 是 B 类实例,visibilityTest() 作为 A 的成员方法,在其内部访问 A.n 完全合法;B 类自身无法直接访问 A.n,但通过继承来的方法可以。
✅ 总结可见性原则:
“方法在哪定义,就以哪的权限规则为准;调用时只检查引用类型是否允许访问该方法,不重新校验方法体内的字段访问。”
四、完整示例验证(含输出说明)
public class Test {
public static void main(String[] args) {
A a = new A(3); // A.m = 3
A b = new B(1, 4); // super(4) → A.m = 4; B.m = 1+1 = 2
System.out.println("Before b.methodOne(6):");
// 注意:无法直接访问 private m,此处为示意逻辑
// 实际中可通过添加 public getM() 辅助观察
b.methodOne(6); // 执行:A.m -= 6 → 4-6 = -2;然后 B.increase(6) → B.m += 6 → 2+6 = 8
System.out.println("After b.methodOne(6): A.m = -2, B.m = 8");
// 验证:A.m 和 B.m 是两个独立变量
}
}? 输出印证:A.m 变为 -2(被 methodOne 修改),B.m 变为 8(被 B.increase 修改)——清晰区分字段隐藏与方法重写的协同效果。
结语:把握三个关键维度
| 维度 | 决定因素 | 示例说明 |
|---|---|---|
| 字段访问 | 编译时静态类型 + 字段声明位置 | methodOne 中的 m 永远指 A.m |
| 方法调用 | 运行时动态类型(对象真实类型) | b.increase() → 实际执行 B.increase |
| 可见性检查 | 方法定义所在的类 | A.visibilityTest() 内可自由用 A.n |
理解这三者的分离与协作,是写出健壮、可预测的继承结构的前提。切记:字段看定义,方法看实例,权限看声明处。








