同包内访问protected成员完全开放,无继承要求;子类访问分同包(可直接访问)和跨包(仅限this或子类实例);非子类跨包一律禁止;static protected访问更宽松,跨包子类可通过类名直接调用。

同包内访问protected成员:完全开放,无继承要求
只要两个类在同一个package下,无论有没有继承关系,都可以直接访问对方的protected成员。
比如父类Fu和工具类Helper都在com.utils包里,Helper哪怕没继承Fu,也能通过new Fu().name读写Fu的protected String name——这和default(包级私有)权限效果一致。
这种设计便于同包协作,但也意味着封装性较弱:包内任意类都能修改受保护字段,不依赖继承机制。
子类访问protected成员:分同包/跨包,规则不同
子类能否访问父类protected成员,关键看是否跨包:
-
同包子类:可以直接访问,且不限调用方式——既可通过
this访问继承来的成员,也可通过父类实例(如new Fu().name)直接访问 -
跨包子类:只能通过
this或子类实例访问自己从父类继承来的protected成员;不能用父类实例访问,例如new Fu().name会编译报错
本质是:跨包时,protected只允许“子类作为自身”去用这个成员,不允许“当作父类的外部使用者”去操作它。
非子类跨包访问:一律禁止
如果一个类和父类不在同一包,又没有继承关系,那它对父类的protected成员完全不可见。
例如:Fu在com.father,Other在com.other且未继承Fu,那么即使写了import com.father.Fu;,new Fu().name或Fu.class.getDeclaredField("name")都会失败——前者编译不通过,后者运行时抛IllegalAccessException(反射也受访问控制限制)。
这和default权限形成对比:default连同包子类都拦住,而protected至少给跨包子类留了入口。
static protected成员的访问更宽松
静态的protected成员不受“必须通过子类实例”的限制。
跨包子类中,既可以用this.staticField,也可以用Fu.staticField,甚至能在静态方法里直接写Fu.staticMethod()——因为static属于类本身,不绑定具体对象,编译器只检查访问者是否为子类,不校验调用表达式的实际类型。
这点常被忽略:非静态protected强调“谁在调”,静态protected只看“谁在写”。

















