子类可直接访问继承的protected成员,但不能通过父类引用跨包访问;protected语义为“包内可见+子类继承可见”,访问权限编译时依据引用类型判定。

在 Java 继承体系中,子类可以直接访问父类被 protected 修饰的成员(字段或方法),但需满足两个关键前提:必须通过继承关系访问,且不能跨包通过父类实例间接访问(除非是同一个包)。
protected 成员的访问规则
protected 修饰符的语义是“包内可见 + 子类可见”,但它不是无条件的“子类任意访问”。Java 规定:
- 子类可以访问自身继承来的
protected成员(即通过this或直接写名称); - 子类不能通过一个父类类型的引用(哪怕实际指向子类对象)访问其
protected成员,除非该引用与当前子类在同一个包中; - 不同包中的子类,只能访问“自己继承得到的”那份 protected 成员,不能访问其他父类实例(即使是同类型)的 protected 成员。
正确访问方式:直接继承调用
只要子类和父类不在同一包,仍可在子类中直接使用 protected 成员,前提是它已被继承:
// 父类(假设在包 com.example.base)
package com.example.base;
public class Parent {
protected int value = 42;
protected void show() {
System.out.println("Parent.show");
}
}
// 子类(在另一个包 com.example.child)
package com.example.child;
import com.example.base.Parent;
public class Child extends Parent {
public void useProtected() {
// ✅ 正确:访问继承来的 protected 字段和方法
System.out.println(value); // 直接访问
show(); // 直接调用
// ✅ 也可显式用 this(效果相同)
System.out.println(this.value);
this.show();
}
}
常见错误:试图通过父类引用来访问
以下写法在不同包中会编译失败,即使实际对象是子类实例:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
public void wrongAccess() {
Parent p = new Child(); // 父类引用指向子类对象
// ❌ 编译错误:value 和 show() 在 com.example.child 中不可见
// System.out.println(p.value);
// p.show();
}
原因:访问权限检查发生在编译时,依据的是引用类型(Parent)的声明位置,而非运行时实际类型。而 Parent 类在另一个包中,其 protected 成员对当前包的 Child 类而言,仅允许通过继承链访问,不允许通过外部引用访问。
绕过限制的合法方式(如需操作其他父类实例)
若确实需要让子类能访问其他父类实例的 protected 成员,可通过以下方式:
- 提供 public 的受控访问方法:在父类中添加 public 方法封装 protected 成员的读写;
-
将子类与父类放在同一包:此时
protected等价于包级访问,可自由通过引用访问; -
利用反射(不推荐日常使用):通过
setAccessible(true)强行访问,但破坏封装性,且受模块系统和安全管理器限制。
本质上,protected 不是“子类万能钥匙”,而是“继承专属通道”。理解这一点,就能避开多数访问异常。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










