java 中子类重写方法时,访问权限不能扩大,只能保持不变或变得更严格(缩小)。这是为了保证多态的安全性,确保父类引用指向子类对象时,原本通过父类可见的方法调用依然有效。如果允许权限扩大,虽然编译能通过,但会破坏 liskov 替换原则的隐含契约,导致代码逻辑混乱。

为什么 Java 禁止在重写时扩大访问权限?
因为 Java 的多态机制依赖于父类引用可以指向子类对象。如果子类重写了父类的 `public` 方法并将其改为 `private`,那么当使用父类类型调用该方法时,编译器会检查父类的签名,发现它是 `public` 从而允许调用,但在运行时如果强制转换为子类类型去执行,可能会遇到权限问题或者逻辑上的不一致。更核心的原因是,父类定义了公共接口,子类作为其实现,必须保持这个接口的可见性不低于父类,否则外部依赖父类接口的代码在替换为子类实例后可能无法正常工作(尽管在 Java 中主要是编译期检查阻止了这一点)。

public class Parent {
public void show() {
System.out.println("Parent show");
}
}
public class Child extends Parent {
// 错误:试图将访问权限从 public 缩小为 protected
// @Override
// protected void show() {
// System.out.println("Child show");
// }
// 正确:保持权限不变
@Override
public void show() {
System.out.println("Child show");
}
}
子类重写方法时访问权限缩小的情况有哪些?
子类重写方法时,访问权限可以缩小,即从 `public` 变为 `protected`、`default`(包私有)或 `private`,但这通常只在特定场景下合法,且主要受限于父类方法的原始权限。例如,如果父类方法是 `protected`,子类可以将其重写为 `protected` 或 `public`(注意:这里其实是扩大了,但 Java 允许子类方法比父类方法更宽松吗?不,Java 规定子类重写方法的访问权限不能比父类更严格,但可以更宽松?让我重新确认一下 Java 规范。根据 JLS 8.4.8.3,子类中覆盖方法的访问权限不能低于被覆盖方法的访问权限。也就是说,如果父类是 `protected`,子类可以是 `protected` 或 `public`。如果父类是 `public`,子类只能是 `public`。所以,子类不能将 `public` 缩小为 `protected`。但是,如果父类是 `default`,子类可以是 `default`、`protected` 或 `public`。因此,子类重写方法时,访问权限可以“扩大”(变得更公开),但不能“缩小”(变得更私有)。等等,我之前的回答第一句说“不能扩大”,这是错误的。正确的规则是:子类重写方法的访问权限不能比父类更严格(即不能缩小),但可以更宽松(即可以扩大)。例如,父类 `protected`,子类 `public` 是合法的。父类 `public`,子类 `public` 是合法的。父类 `public`,子类 `protected` 是不合法的。所以,题目问“能扩大吗”,答案是“能”。我需要修正我的思考。Java 允许子类重写方法时扩大访问权限,只要新权限比旧权限更公开。例如,父类方法是 `protected`,子类重写为 `public` 是允许的。这是因为子类提供了更强的可见性,不会破坏父类定义的契约。相反,如果子类缩小权限,比如父类 `public`,子类 `private`,那么通过父类引用调用该方法时会失败,因为父类声明它是公开的,但实际执行时却是私有的,这违反了类型安全。因此,正确答案是:Java 中子类重写方法时,访问权限可以扩大,但不能缩小。

class Base {
protected void method() {
System.out.println("Base");
}
}
class Derived extends Base {
// 合法:从 protected 扩大到 public
@Override
public void method() {
System.out.println("Derived");
}
}
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











