方法重写是子类在运行时接管父类方法调用,要求签名完全一致(方法名、参数列表、擦除后类型)、返回类型协变、访问修饰符不更严格,必须用@override防错,运行时行为由实际对象类型决定而非变量声明类型。

方法重写不是给父类方法换个名字,而是让子类在运行时“接管”调用逻辑——关键在于签名严丝合缝、对象类型决定行为、变量声明只管编译不控执行。
签名必须一字不差:方法名、参数列表、返回类型
重写生效的前提是 JVM 能准确识别“这是同一个方法”。哪怕一个细节偏差,就变成重载或新方法,多态立刻失效。
- 方法名、参数个数、每个参数的原始类型(泛型擦除后)必须完全一致。例如父类是 void save(List
data) ,子类写成 void save(ArrayListdata) —— 这是重载,不是重写 - 返回类型允许协变:父类返回 Animal,子类可返回 Dog;但不能把 int 改成 Integer,也不能把 Object 改成 String(非父子关系)
- 访问修饰符不能更严格:父类是 protected,子类不能用 private 或包级私有;但可以升级为 public
@Override 注解不是可选,是防错刚需
它不参与运行,但会在编译阶段揪出所有“假重写”:拼错方法名、参数类型写反、父类方法已被删除……没它,bug 隐蔽得极深。
- 一旦加了 @Override 却编译失败,说明你根本没重写成功——别改调用方,先校验签名
- IDE 自动生成重写方法时默认带该注解,应养成“手写也补上”的习惯
- 常见误判:父类方法是 private,子类同名方法加 @Override 会直接报错,这正是它在提醒你“不可见,谈不上重写”
变量类型只影响编译,对象类型才决定运行时走哪条路
声明为 Animal a = new Dog(),编译器只认 Animal 里有的方法;但一运行,JVM 看的是堆里那个真实对象——Dog 实例,自动跳转到 Dog 的重写版本。
- 若子类新增了 bark() 方法,用 Animal 类型变量无法调用,必须显式转型:((Dog) a).bark()
- 即使把变量改成 Dog d = new Dog(),只要方法本身是重写的,其行为逻辑仍由对象实例决定,和变量名无关
- 构造器中调用将被重写的方法是高危操作:此时子类字段尚未初始化,JVM 仍走父类逻辑,极易触发 NullPointerException
要不要 super.xxx()?取决于业务语义,而非语法强制
重写是覆盖,不是追加。是否复用父类逻辑,由你设计,JVM 不干预。但漏掉关键步骤(如资源清理、字段初始化)常因忘记 super 调用。
- 需要扩展时才调用:toString() 中想保留父类字段,就在开头写 super.toString();close() 中需释放父类持有的资源,结尾加 super.close()
- super 只能在非 static、非 private、非 final 的实例方法中使用
- 如果父类方法声明了受检异常,子类重写时只能抛出相同异常或其子类,否则编译失败










