子类重写方法时访问权限不能收紧,必须持平或放宽,否则违反里氏替换原则。Java 编译期强制检查,如父类 public 方法在子类中改为 protected 会报错“Cannot reduce the visibility”。

因为这会直接破坏多态调用的安全性,违反里氏替换原则(LSP)。
核心原因:保障父类引用能正常调用子类方法
Java 允许用父类类型引用指向子类对象,比如 Animal a = new Dog();。此时调用 a.makeSound(),实际执行的是子类重写后的方法。但如果子类把原本 public 的方法改成 protected 或包私有,编译器就无法保证这一调用在所有上下文中都合法——外部代码本可通过父类引用访问该方法,却因子类收窄权限而失败。
权限等级不可逆:public > protected > 默认 > private
Java 明确规定子类重写时的访问修饰符只能持平或放宽,不能收紧:
- 父类是 public → 子类必须是 public
- 父类是 protected → 子类可选 protected 或 public,但不能是默认或 private
- 父类是默认(包私有)→ 子类可选默认、protected 或 public,但不能是 private
- 父类是 private → 不可重写,子类中同名方法只是独立声明,与继承无关
这不是运行时问题,而是编译期强制检查
一旦越权,编译器立刻报错,典型提示为:Cannot reduce the visibility of the inherited method from XXX。错误位置精准指向子类方法定义行,不依赖 IDE 提示——很多自动生成功能(如 @Override 模板)默认加 public,手动删掉就容易踩坑。
接口实现和抽象方法同样适用
接口中所有方法默认 public,所以实现类中 @Override 的方法也必须是 public;抽象方法被子类实现时,也不能收窄权限。这些规则统一服务于同一个目标:确保任何符合父类契约的地方,子类都能无缝替代。

















