protected 是继承可见性控制:同包类可直接访问(无视继承),子类访问则分同包(完全自由)与跨包(仅限自身实例或super调用);static protected成员跨包也可直接访问;应避免暴露protected字段,推荐private字段+protected getter。

protected 在 Java 中不是“跨包开放”,而是“继承可见性控制”——它让同包类和子类都能访问,但规则完全不同:同包看位置,子类看身份和调用方式。
同包内访问:不看继承,只看包名
只要两个类在同一个 package 下,无论有没有继承关系,都可以直接访问对方的 protected 成员:
- 工具类 Helper 没继承 Parent,也能写
new Parent().value读写其 protected int value - 这种访问等效于 default(包级私有) 权限,编译器不检查是否为子类
- 风险在于封装性弱:包内任意类都可修改字段,破坏父类不变量
子类访问:分同包/跨包,关键看“谁在访问、通过什么访问”
子类能否访问父类 protected 成员,取决于是否跨包以及访问主体:
-
同包子类:完全自由——可用
this.value、super.value、new Parent().value、new Child().value,全部编译通过 -
跨包子类:只允许访问“自己继承链上的对象”:
- ✅
this.value或new Child().value—— 当前类实例,合法 - ✅
super.value—— 显式调用父类版本,清晰且推荐 - ❌
new Parent().value—— 编译报错:“has protected access in Parent”
- ✅
static protected 成员:规则更宽松
静态成员不绑定实例,所以跨包子类访问不受“必须通过子类实例”的限制:
立即学习“Java免费学习笔记(深入)”;
- 可在子类中直接写
Parent.STATIC_FIELD或this.STATIC_FIELD - 静态方法里也能调用
Parent.staticMethod(),无需实例 - 本质区别:非静态 protected 看“调用表达式的实际类型”,静态只看“当前类是否为子类”
安全实践建议:别直接暴露字段
把 protected 字段当公共接口用,容易导致子类绕过校验、破坏状态一致性。更可控的做法是:
- 字段设为 private,提供 protected final String getXXX() 方法
- 关键逻辑(如校验、日志、懒加载)封装在 getter 中
- 若需外部统一获取能力,定义接口(如 DataProvider),由父类实现,子类自动获得契约保障


















