重写方法时子类签名必须与父类完全一致,包括方法名、参数类型和数量(基本类型与包装类不兼容)、返回类型(支持协变),访问修饰符不能更严格,异常声明不能更宽泛;必须使用@override注解强制校验,否则可能重写失效;tostring()、equals()、hashcode()等需遵循特定约定;final、static和构造方法不可重写。

重写方法时,子类签名必须和父类完全一致
Java 编译器只看方法名、参数类型和数量、返回类型(协变除外)是否匹配,@Override 注解不是装饰用的,而是强制校验。一旦参数类型写成 Integer 而父类是 int,或加了额外参数,编译直接报错:method does not override or implement a method from a supertype。
- 参数顺序、类型、个数一个都不能差;泛型擦除后类型要一致,比如
List<string></string>和List<object></object>不能算重写 - 返回类型可以是父类返回类型的子类型(协变返回),比如父类返回
Object,子类可返回String;但反过来不行 - 访问修饰符不能更严格:父类是
protected,子类不能写private;但可以更宽松,比如改成public - 不能抛出比父类方法更多或更宽泛的检查异常(
Exception),但可以抛出更具体的(IOException→FileNotFoundException)或不抛
没加 @Override 注解,重写可能根本没生效
这是最隐蔽的坑——你自以为重写了,其实只是在子类里“恰好”定义了一个同名方法。没有 @Override,编译器不会帮你核对签名,也不会报错。运行时调用的还是父类方法,多态失效,逻辑出错却难以定位。
- 永远在打算重写的方法上显式加上
@Override;IDE 通常能自动补全,别手懒删掉 - 如果加了
@Override却编译失败,说明签名不匹配,立刻检查参数类型(尤其是基本类型 vs 包装类)、拼写、大小写 - 抽象方法实现也必须加
@Override;接口默认方法被重写时同样适用
重写 toString()、equals()、hashCode() 有特殊约定
这些方法来自 Object,但语义敏感。随便重写可能导致集合行为异常(比如 HashMap 找不到 key)、日志输出不可读、单元测试失败。
-
toString()应该返回简洁、可读、不含敏感信息的字符串;避免递归调用或大对象深遍历 -
equals()必须满足自反性、对称性、传递性、一致性;推荐用Objects.equals(a, b)比较字段,先判null和this == obj -
hashCode()必须和equals()保持一致:两个对象equals()返回true,则它们的hashCode()必须相等;建议用Objects.hash(field1, field2)生成
final 方法、static 方法、构造方法不能被重写
Java 明确禁止这三类方法参与多态分派。试图重写会触发编译错误,而不是运行时行为差异。
-
final void doWork()在父类中 → 子类里写同签名方法,编译报错:cannot override final method -
static void log()→ 子类写同签名static方法,属于隐藏(hiding),不是重写;调用取决于引用类型,不是实际对象类型 - 构造方法天生不属于继承链,子类构造器只能通过
super()调用父类构造器,不存在“重写”概念
多态靠的是运行时动态绑定,而 final/static/构造方法的绑定都在编译期或类加载期完成。想绕过这个限制,通常说明设计有问题——要么该用组合代替继承,要么该把逻辑抽到可重写的方法里。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











