子类重写父类方法必须同时满足四条规则:方法签名完全一致、返回值类型兼容(协变)、访问权限不更严格、检查型异常声明不更宽泛;违反任一规则将导致重写失败。

子类重写父类方法不是“名字一样就能覆盖”,而是有四条不可逾越的硬性规则。违反任意一条,要么编译直接报错,要么看似运行、实则未真正重写(比如变成重载或隐藏),导致多态失效、逻辑出错。
方法签名必须完全一致
这是重写的起点和底线。方法签名 = 方法名 + 参数列表(参数类型、个数、顺序),三者缺一不可地相同。
- 仅改返回值类型?❌ 不算重写(编译可能通过,但实际是新方法)
- 参数类型从 int 改成 Integer?❌ 是重载,不是重写(包装类与基本类型属于不同参数类型)
- 加了个默认值参数?❌ Java 没有默认参数,添加任何新参数都破坏签名
- 建议始终加上 @Override 注解——编译器会立刻帮你揪出签名不匹配的问题
返回值类型必须兼容(协变规则)
返回值不能“扩大”,但允许“缩小”——这是 Java 5 起支持的协变返回类型。
- 父类返回 void 或基本类型(如 int、boolean)→ 子类必须严格一致
- 父类返回引用类型(如 Animal)→ 子类可返回其子类(如 Dog、Cat)
- 反向操作(如父类返回 Object,子类返回 String)?✅ 允许(String 是 Object 子类)
- 但父类返回 String,子类返回 Object?❌ 编译失败(扩大了返回范围)
访问权限不能更严格
子类方法的可见性只能等于或高于父类,否则破坏里氏替换原则:用父类引用调用时,子类对象反而不可见。
- 父类是 public → 子类只能 public
- 父类是 protected → 子类可 protected 或 public,不可 default(包私有)或 private
- 父类是 default(无修饰符)→ 子类可 default、protected 或 public
- 父类是 private → ❌ 根本不可继承,谈不上重写(子类同名方法是独立新方法)
异常声明不能更宽泛
只约束 检查型异常(Checked Exception);运行时异常(如 NullPointerException)不受限。
- 父类没声明任何 checked 异常 → 子类不能抛 IOException、SQLException 等,但可抛 RuntimeException 及其子类
- 父类声明 IOException → 子类可抛 FileNotFoundException(它是 IOException 子类),或不抛,但不可抛 Exception(更宽泛)或 SQLException(无关类型)
- 子类方法可以比父类抛得更少、更具体,但绝不能更多、更笼统











