
Java 中字段不支持多态,子类同名字段会隐藏父类字段;而方法支持运行时多态,重写后调用的是子类实现——这是理解 sub.m() 输出父类字段值的关键。
java 中字段不支持多态,子类同名字段会隐藏父类字段;而方法支持运行时多态,重写后调用的是子类实现——这是理解 `sub.m()` 输出父类字段值的关键。
在 Java 中,字段(成员变量)和方法遵循完全不同的绑定规则:字段是静态绑定(编译期决定),而实例方法是动态绑定(运行期决定)。这一根本差异直接导致了你在示例中观察到的“意外输出”。
字段隐藏(Field Hiding):静态、非多态
当子类声明一个与父类同名的字段(如 String i),它并不会覆盖(override)父类字段,而是隐藏(hide)它。两个字段物理上同时存在:Super.i 和 Sub.i 是独立的存储空间。在 Super.m() 方法体内,i 的引用始终解析为 Super 类作用域中的 i —— 因为该方法是在 Super 中定义的,其字节码指令明确访问的是 Super 类的字段槽位(field slot)。即使通过 Sub 实例调用,m() 仍是 Super 的原始版本,自然打印 "Variable of superclass"。
Sub sub = new Sub(); System.out.println(sub.i); // 输出 "Variable of subclass"(访问 Sub.i) System.out.println(((Super)sub).i); // 输出 "Variable of superclass"(强制类型转换后访问 Super.i)
方法重写(Method Overriding):动态、多态
当你取消注释 @Override void m(),Sub 提供了自己的 m() 实现。此时:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 调用
sub.m()将执行Sub.m(); - 其内部
System.out.println(i)中的i在Sub作用域内解析,故访问的是Sub.i; - 即使方法体内容与父类完全相同,重写行为本身改变了方法的归属类,从而改变了字段解析上下文。
class Sub extends Super {
String i = "Variable of subclass";
@Override
void m() {
System.out.println(i); // ✅ 解析为 Sub.i(当前类字段)
}
}
关键对比总结
| 特性 | 字段(Field) | 实例方法(Instance Method) |
|---|---|---|
| 绑定时机 | 编译期(静态绑定) | 运行期(动态绑定) |
| 多态支持 | ❌ 不支持(仅隐藏) | ✅ 支持(可重写) |
| 访问依据 | 引用变量的声明类型 | 实际对象的运行时类型 |
| 推荐实践 | 避免同名字段;优先使用 private + getter/setter |
合理设计继承层次,善用 @Override
|
⚠️ 注意:字段隐藏易引发歧义,应尽量避免。若需不同行为,请通过抽象方法或模板方法模式实现,而非依赖字段同名。例如,将
i设为private并提供getI()模板方法,由子类重写getI()返回对应值——这才是面向对象的正确抽象方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










