Java中子类重写父类方法时访问权限只能持平或放宽,不可缩小——这是编译器强制规则,旨在保障多态安全与里氏替换原则;public必须保持public,protected可升为public,包私有可升为protected/public,private方法不参与重写。

Java 中不能通过方法重写(Override)来扩大或缩小父类方法的访问权限,这是编译器强制限制的规则。重写方法的访问修饰符只能与父类方法相同,或者更宽松(即权限更大),但不能更严格。
访问权限的合法变更方向
Java 规定:子类重写方法的访问修饰符必须 ≥ 父类方法的访问级别。也就是说:
- 父类是 private → 无法被继承,也就谈不上重写(子类中定义同名方法属于新方法,不是重写)
- 父类是 default(包级私有)→ 子类重写方法可以是 default、protected 或 public
- 父类是 protected → 子类重写方法可以是 protected 或 public,但不能是 default 或 private
- 父类是 public → 子类重写方法必须是 public(不能降级)
为什么不能降低访问权限?
这是为了满足里氏替换原则(Liskov Substitution Principle)。如果子类把父类 public 方法改成 private 或 protected,那么原本能通过父类引用调用该方法的代码,在运行时换成子类实例后就会因访问失败而编译报错或行为异常,破坏了多态的安全性。
例如:若 Animal.speak() 是 public,而 Dog.speak() 被设为 private,那么 Animal a = new Dog(); a.speak(); 就会出问题——编译器允许调用(因为 Animal 声明了 public 方法),但实际执行时却不可见。
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
立即学习“Java免费学习笔记(深入)”;
常见错误示例
以下代码无法通过编译:
class Parent {
protected void show() { }
}
class Child extends Parent {
@Override
void show() { } // 编译错误:试图将 protected 降级为 default(包访问)
}
同样,下面也不允许:
class Parent {
public void run() { }
}
class Child extends Parent {
@Override
protected void run() { } // 编译错误:public → protected 是降级
}
实际开发中的建议
设计父类方法时,应提前考虑子类扩展需求,合理选择初始访问级别:
- 确定要被子类重写的模板方法,优先声明为 protected(比 public 更安全,又保留扩展性)
- 对外提供的稳定接口方法,用 public,并避免在子类中削弱其可见性
- 如需隐藏实现细节,不要依赖访问修饰符“降级”来控制,而应通过组合、接口抽象或 final 方法等方式约束

















