子类覆盖父类方法需遵循override原则:保持接口契约不变,仅调整内部实现;必须使用@override注解校验签名一致性;父类方法须非private、非static、非final;子类访问权限不能更严格;支持协变返回类型;优先复用super调用以增强逻辑,避免重复造轮子。

子类实现父类功能的逻辑变更,核心在于覆盖(Override)而非重写(Rewrite)——它不是推翻父类设计,而是在继承基础上,有意识地调整行为细节,保持接口契约不变,只改变内部实现。
明确覆盖意图:用 @Override 注解强制校验
Java 要求子类方法签名(名称、参数类型、返回类型)与父类被覆盖方法完全一致。添加 @Override 注解不仅是规范,更是编译期保护:一旦父类方法名拼错、参数改了或访问权限收紧,编译器立刻报错,避免“看似覆盖实则重载”的静默失败。
- 父类中方法必须是 非 private、非 static、非 final 的,否则无法被覆盖
- 子类方法访问权限不能比父类更严格(如父类是
protected,子类不能是private) - 返回类型支持协变返回(子类方法可返回父类返回类型的子类型),但参数类型必须严格一致
变更逻辑时保留父类行为的可控接入点
并非所有变更都要从头写。若新逻辑只是在原有流程中增删步骤,优先考虑调用 super.methodName() 复用父类实现,再做增强或拦截。
- 例如:父类
save()完成数据持久化;子类覆盖后先校验权限,再调用super.save(),最后发通知 - 避免重复造轮子,也降低因遗漏关键步骤(如事务开启、资源释放)引发的 bug
- 若父类方法逻辑已不适用(如算法彻底更换),则不调用
super,但需确保外部调用者感知不到契约破坏
注意多态调用下的实际执行路径
运行时决定调用哪个版本的方法,取决于对象的实际类型,而非引用类型。这点常被忽略,导致“以为调用了子类逻辑,实际走的是父类”。
-
Parent p = new Child(); p.doWork();→ 执行的是Child.doWork() - 若父类方法被声明为
final或是static,则永远绑定到声明类型,不参与动态分派 - 构造器中调用可覆盖方法要格外谨慎——此时子类实例尚未初始化完成,可能导致空指针或状态不一致
配合模板方法模式,把可变逻辑“挖空”出来
当父类定义了固定骨架(如“连接→执行→关闭”),而具体步骤因子类而异,适合用模板方法:父类提供 final 模板方法,把变化点抽成 protected abstract 或默认空实现的钩子方法,由子类选择性覆盖。
- 这样既控制流程主干,又把逻辑变更限定在明确、有限的扩展点上
- 比直接覆盖整个方法更安全,也更易维护和测试
- 避免子类无意中破坏关键顺序(比如跳过清理步骤)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











