子类重写父类方法时访问修饰符不能比父类更严格:public只能重写为public,protected可重写为protected或public,但不可降为private或默认(包私有);private方法不可重写,仅隐藏;protected重写为默认修饰符将编译失败。

子类重写方法时访问修饰符不能比父类更严格
Java 中,子类重写父类方法时,public 可以重写为 public,protected 可以重写为 protected 或 public,但绝不能降级为 private 或包私有(即不写修饰符)。编译器会直接报错,不是运行时问题。
-
private方法不能被重写(本质是隐藏),所以子类里写个同名private方法,和父类完全无关 - 父类是
protected,子类用默认(包访问)修饰符:编译失败 —— 包访问权限 protected - 父类是
public,子类写成protected:编译失败 —— 违反“子类方法契约不能收缩”原则
为什么 Java 要强制这个限制
这是为了保障里氏替换原则(LSP):任何父类出现的地方,子类都能安全替换。如果子类把方法从 public 改成 protected,外部代码调用父类引用指向子类实例时,原来能调的方法突然不可见了,逻辑直接崩。
- 接口实现也适用同一规则:实现类中
@Override的方法,访问权限必须至少是public(接口方法默认public) - 抽象方法被重写时同样受约束,哪怕父类是
protected abstract,子类实现也不能收窄 - IDE 通常不会提示这个错误,直到编译 —— 所以别依赖自动补全来判断权限是否合法
常见报错信息和定位方式
编译时会明确告诉你哪一行越权了,错误信息长这样:Cannot reduce the visibility of the inherited method from XXX。重点看 “inherited method” 后面的类名和方法签名。
- 检查父类方法声明位置,确认它的实际修饰符(注意继承链中可能被中间类改过)
- 确认子类方法上没多写
private、protected(当父类是public时) - 留意 IDE 自动生成功能(如 Eclipse/IntelliJ 的 Override 生成)有时会默认加
public,但如果你手动删了,就容易踩坑
特殊情况:static 和 final 方法不参与重写
static 方法是静态绑定,子类里“同名”只是隐藏(hiding),不受访问权限限制规则约束;final 方法不能被重写,所以谈不上权限变化。这两类都不会触发上面的编译错误。
- 子类写
static void foo(),父类也有static void foo():不报错,但不是重写,调用取决于引用类型 - 子类试图
@Override一个final方法:编译错误是method is final,和权限无关 - 误以为
private方法能被重写,然后在子类里调用不到 —— 实际是两个独立方法,彼此不可见
public,子类重写时无脑写 public;父类是 protected,子类优先用 public,除非你明确需要限制调用范围且已评估所有继承路径。










