protected成员在同包内对所有类可见,跨包时仅对继承链上的子类开放;子类必须与父类同包才能直接访问,跨包只能通过this/super调用,不可通过父类引用调用。

protected 在同一包内子类中可以直接访问
protected 成员在定义它的类所在包内,对所有类(包括非子类)都可见;但一旦跨包,就只对继承链上的子类开放。所以如果你写了个子类和父类在同一个包里,哪怕没用 extends 显式继承,只要它是子类(即用了 extends),就能直接用父类的 protected 字段或方法。
常见错误现象:javac 报错 error: protectedMethod() has protected access in Parent,但明明写了 extends Parent —— 很可能父类和子类不在同一包,或者子类文件没正确声明 package。
使用场景:想让包内协作类自由调用某些“半公开”逻辑,同时又为跨包子类留出扩展入口。
- 确保父子类
package声明完全一致(注意空格、大小写) - 不要依赖 IDE 自动生成的包路径,手动检查
.java文件顶部的package行 - 同一包下非子类也能访问
protected成员,这不是 bug,是 Java 规范行为
跨包子类只能通过继承关系访问 protected 成员
跨包时,protected 成员对外部包的所有类(包括该包内的子类)都不具备“包级可见性”,仅保留“继承可见性”。也就是说,子类可以调用,但不能通过父类实例引用去调。
立即学习“Java免费学习笔记(深入)”;
常见错误现象:Parent p = new Child(); p.protectedMethod(); // 编译失败
即使 Child 是 Parent 的子类且在不同包,这行也会报错 —— 因为访问发生在 Parent 类型引用上,不是 Child 自身上下文。
性能 / 兼容性影响:无运行时开销,纯编译期检查;所有 JDK 版本行为一致。
- 只能在子类内部直接写
this.protectedMethod()或super.protectedMethod() - 不能用
new Parent().protectedMethod(),也不能用其他包内对象引用调用 - 如果需要从外部调用,得加 public 方法做桥接,而不是改访问符
子类重写 protected 方法后,其可见性不能降低
子类重写(override)父类 protected 方法时,重写后的方法访问级别只能是 protected 或 public,不能是 private 或包私有(即不加修饰符)。
常见错误现象:error: attempting to assign weaker access privileges,通常出现在你试图把父类的 protected void foo() 改成 void foo()(默认包私有)或 private void foo()。
参数差异:重写不要求参数变,但若参数类型涉及泛型或子类,需满足协变规则;不过这和访问控制无关,此处不展开。
- 重写时加
public是安全的,甚至推荐(尤其当你希望子类能力被更广范围使用) - 不加修饰符(默认包私有)是常见误操作,IDE 有时不会高亮提醒,但
javac一定报错 - 静态方法不存在“重写”,只有隐藏(hiding),所以
static protected方法在子类中用同名方法会绕过该限制 —— 但这不是重写,别混淆
内部类访问外部类的 protected 成员不受包限制
非静态内部类(inner class)属于外部类的“扩展部分”,它访问外部类的 protected 成员时,不走常规继承或包规则,而是按“同一个顶层类作用域”处理。哪怕外部类是 protected,内部类也能直接访问。
容易被忽略的地方:这个行为常被当成理所当然,但一旦你把内部类抽成独立顶层类(哪怕仍继承原外部类),规则立刻回归标准 —— 此时就受跨包限制了。
- 匿名内部类、局部内部类同样适用此规则
- 静态嵌套类(
static class)不享有该特权,它和普通跨包子类一样,必须靠继承才能访问 - 如果你在内部类里写
Outer.this.protectedField,没问题;但换成new Outer().protectedField,就会因包限制而失败(除非同包)
事情说清了就结束。








