子类重写方法时签名必须完全一致,包括方法名、参数类型与顺序、返回类型(协变除外)及异常声明;构造器、静态方法、final/private方法不可重写;需显式调用super以安全扩展父类逻辑。

子类重写方法时,签名必须完全一致
Java 和 C# 等静态语言里,override 不是“名字一样就行”,而是要求方法名、参数类型与顺序、返回类型(协变除外)、异常声明(Java)全部匹配。C++ 中还要注意 virtual 和 override 关键字是否显式标注,否则可能只是定义了新函数,没真正重写。
常见错误现象:Method does not override method from its superclass(Java)、'func' marked 'override' but does not override any method(Swift)、或运行时调用的仍是父类版本(C++ 忘加 virtual)。
- Java:子类
toString()返回String,就不能改成返回Object;但可以改为返回StringBuilder(协变返回,JDK 5+ 支持) - C#:若父类是
public virtual void Log(string msg),子类必须写public override void Log(string msg);把string换成object就是重载,不是重写 - Python 没有语法级
override标记,但用@override装饰器(来自typing)可触发 IDE 检查,推荐加上
重写后如何安全调用父类逻辑
很多场景下不是“替换”,而是“扩展”——比如在子类方法开头加日志、结尾做清理。这时候必须显式调用 super,但不同语言写法差异大,容易漏或写错。
使用场景:拦截初始化、补充验证、包装返回值、资源释放。
- Java:用
super.methodName(...),必须在子类方法体内,不能放在字段初始化或构造器参数里 - Python:用
super().method_name(...),注意多继承时 MRO(方法解析顺序),super()不等于ParentClass - JavaScript(ES6 class):子类构造器中必须先调用
super(),否则报ReferenceError: Must call super constructor in derived class before accessing 'this'
返回类型不兼容会导致编译失败
返回类型是重写契约的一部分。虽然某些语言支持协变(子类返回更具体的类型),但反过来绝对不行——父类声明返回 List<string></string>,子类不能返回 ArrayList<object></object>。
性能影响:看似只是类型问题,但 JVM/.NET 会为不同签名生成不同字节码/IL,不匹配就无法动态绑定。
- Java:允许协变,
Object get() { ... }可被@Override String get() { ... }重写 - C#:同样支持协变返回,但仅限引用类型;值类型(如
int→long)不行 - TypeScript:接口实现中重写方法,返回类型必须是父类返回类型的子类型,否则类型检查失败
构造器、静态方法、final/private 方法不能被重写
这是初学者最常误踩的点:看到父类有个 init() 或 create(),想“覆盖它”,结果发现根本不起作用——因为它们要么是静态的,要么被 final 锁死,要么属于构造过程本身。
错误现象:Cannot override the final method、Static method cannot be overridden、IDE 提示 “no override available”。
- Java:
private方法隐式final,子类同名方法只是新定义;static方法只能被“隐藏”(hiding),不是重写 - Python:没有
final语法,但可用@final(typing模块)配合类型检查器提醒;__init__是构造器,可重写,但必须调用super().__init__()来保证父类初始化 - Go 没有传统重写机制,靠组合 + 接口实现类似效果,所谓“重写”其实是嵌入字段后提供同名方法,本质是替换委托对象
重写的边界比看起来窄:它只发生在虚方法调用路径上,而这个路径从声明位置、访问修饰符、语言运行时规则就开始决定了。漏掉一个 virtual、多写一个 static、或者以为 Python 的 def __str__ 能绕过 MRO,都可能让重写失效。









