protected跨包访问需满足三前提:子类继承父类、在实例方法/构造器中访问、目标为this或本类实例;禁止静态上下文、父类引用或纯父类实例调用。

Java 中 protected 修饰符跨包使用,关键不是“能不能访问”,而是“谁在什么上下文中、以什么方式访问”。它不开放跨包任意调用,只允许子类在继承链内部自然使用——本质是继承可见性控制,不是跨包通行证。
必须满足的三个前提条件
跨包访问 protected 成员要编译通过,必须同时满足:
- 子类正确 extends 父类(即使在不同包)
- 访问发生在子类的实例方法、构造器或实例初始化块中(不能是静态方法)
- 访问目标必须是当前对象(this)或本类/子类创建的实例,不能是父类类型引用(如
Parent p = new Child())
合法写法:都在子类实例上下文中
假设 Fu 在包 com.father,Zi 在 com.son 并继承 Fu:
-
this.name—— ✅ 直接用,等价于继承来的字段 -
super.name—— ✅ 显式调用父类版本,语义清晰 -
new Zi().name—— ✅ 新建本类实例,仍属同一继承链 -
getName()(若父类提供protected final String getName())—— ✅ 封装后调用,安全可控
典型错误:看似合理,实则编译失败
以下代码哪怕出现在子类 Zi 的方法里,也会报错:
立即学习“Java免费学习笔记(深入)”;
-
new Fu().name→ “Cannot resolve symbol 'name'”(纯父类实例,非继承链上) -
Fu f = new Zi(); f.name→ “has protected access in Fu”(引用类型是Fu,跨包不可见) -
public static void main(...) { new Zi().name; }→ 编译失败(静态上下文,无this)
更推荐的安全实践
直接暴露 protected 字段风险高(同包其他类可改,子类可误赋值)。建议组合使用:
- 字段设为
private,提供protected final String getXXX()—— 子类能读,不能绕过校验 - 用
protected abstract void onReady(Asset asset)把“提取逻辑”交给子类实现,资产本身由父类管控 - 返回不可变视图:
protected List<string> getData() { return Collections.unmodifiableList(data); }</string>


















