Java中protected跨包继承的四大陷阱:一是子类仅能通过this/super或本类实例访问父类protected成员,父类类型变量访问编译失败;二是其本质是继承可见性控制,非跨包开放;三是重写时权限不可降级;四是protected非final字段破坏封装性。

Java 中 protected 在跨包继承时的“坑”,不在于它不能用,而在于它看似能用、实则有严格边界——很多人写了编译报错的代码,还觉得是 IDE 或 JDK 有问题。
坑一:以为“子类就能访问父类 protected 成员”,其实只限“自己继承来的那一份”
跨包子类确实可以访问父类的 protected 字段或方法,但仅限于:
- 在子类的实例方法、构造器或初始化块中,通过
this.field或this.method()直接使用 - 显式写
super.field或super.method() - 用
new Child().field(因为这是本类继承链上的对象)
以下全部编译失败,哪怕对象确实是子类实例:
-
Parent p = new Child(); p.field;→ 报错:"has protected access in Parent" -
new Parent().field;→ 不属于子类继承链,完全不可见 - 同包子类外的其他类(如工具类)试图访问
new Parent().field→ 同样失败
坑二:误把 protected 当成“跨包开放开关”,忽略了它的本质是“继承可见性控制”
protected 的设计目标不是让外部包随意读写父类状态,而是让子类复用实现细节。它的权限判断依据是两个条件:
立即学习“Java免费学习笔记(深入)”;
- 谁在访问? —— 必须是子类自身(即当前类是父类的子类)
- 通过什么主体访问? —— 必须是 this、super 或本类创建的实例,不能是父类类型变量
换句话说:运行时对象是不是子类实例,不重要;编译时变量声明类型是不是父类,才关键。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
坑三:重写时权限变窄,编译直接拒绝
父类方法是 protected void init(),子类重写时写成:
-
void init()(默认权限)→ 编译错误:"attempting to assign weaker access privileges" -
private void init()→ 同样报错
合法重写只能是:
-
protected void init()(保持原权限) -
public void init()(升权)
这条规则在跨包场景下特别容易踩中,因为子类开发者可能没注意到父类方法的修饰符。
坑四:裸露 protected 非 final 字段,导致状态失控
很多同学为图方便,把配置字段直接声明为:
protected String apiKey;
问题在于:
- 同包内任意类都能改它(
protected对同包所有类开放) - 子类可在任何地方随意赋值,绕过校验逻辑
- 破坏父类封装性和不变量保证
更稳妥的做法:
- 字段设为
private final,提供protected final String getApiKey() - 或用
protected void configure(String key)封装修改逻辑

















