protected 的核心是“受控继承”而非开放访问,允许子类(含跨包)在自身代码中直接使用父类 protected 成员,但禁止通过父类引用访问;跨包子类访问需满足继承上下文,对外暴露应封装 getter。

在继承中用 protected 共享数据,核心不是“开放访问”,而是“受控继承”。它允许子类(包括跨包)自然继承并使用父类的关键成员,但禁止通过父类引用随意读写——这是设计意图,不是限制缺陷。
子类内部直接使用 protected 成员
只要子类正确继承了父类,就能在自己的方法体里像访问自己的字段一样使用 protected 成员,无需额外语法或转换。
- 父类中声明:
protected String configPath = "/etc/app.conf"; - 子类中调用:
System.out.println("Config: " + configPath);—— 编译通过,合法 - 也可用
super.configPath显式指明来自父类,尤其当子类有同名字段时
避免用父类类型变量访问子类的 protected 数据
这是最常踩的坑:即使对象实际是子类实例,只要变量声明为父类类型,就不能访问其 protected 成员。
- ❌ 错误写法:
Parent p = new Child(); p.configPath;→ 编译报错 - ✅ 正确写法:
Child c = new Child(); c.configPath;或直接在Child方法内用this.configPath - 原因:Java 检查的是**变量声明类型**,不是运行时对象类型
跨包子类访问必须满足“继承上下文”
protected 不是“跨包可见”,而是“跨包可继承后使用”。关键在于访问是否发生在子类自身代码中,且目标是本类或子类实例。
- ✅
this.configPath、new Child().configPath、super.init()都合法 - ❌
new Parent().configPath、otherChild.configPath(otherChild 是另一个子类实例)、parentRef.configPath都非法 - 不同包的非子类(哪怕同包的其他类)完全无法访问该成员
对外暴露建议封装 getter,而非直接 public 字段
如果需要让外部(比如同包工具类或上层框架)安全读取 protected 数据,应在父类中提供受控入口。
- 推荐:
protected String getConfigPath() { return configPath; } - 子类可重写该方法,加入权限校验或路径拼接逻辑
- 避免把字段设为
public或去掉修饰符——这会破坏封装,导致所有调用方强依赖字段名和类型
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











