Java跨包场景下子类对象无法访问父类protected字段的原因咨询
问题描述
我在学习Java访问修饰符时遇到了困惑,现有如下类:
package first.second; public class Powers { public int ninth = 512; private int tenth = 1024; protected int eleventh = 2048; int twelfth = 4096; public static void main(String args[]){ Powers p = new Powers(); System.out.println(p.tenth); System.out.println(p.ninth); System.out.println(p.eleventh); System.out.println(p.twelfth); } }
另有两个与Powers不同包、但彼此同包的类:
package first; import first.second.Powers; public class SuperPowers extends Powers { public void printPowers () { System.out.println(this.eleventh); // 可以直接访问protected字段 SuperPowers sp = new SuperPowers(); System.out.println(sp.eleventh); // 通过SuperPowers对象访问也可以 // System.out.println(twelfth); // 编译错误 } } package first; import first.second.Powers; public class TestPowers { public static void main(String[] args) { Powers p = new Powers(); System.out.println(p.ninth); //System.out.println(p.tenth); // 编译错误 //System.out.println(p.eleventh); // 编译错误 //System.out.println(p.twelfth); // 编译错误 SuperPowers sp = new SuperPowers(); sp.printPowers(); // 可以通过SuperPowers的方法访问 // System.out.println(sp.eleventh); // 直接访问不行 :( } }
我原本预期可以在TestPowers类中通过SuperPowers对象的点语法访问Powers类的protected字段eleventh,尝试让TestPowers继承Powers也无效,请问原因是什么?
解答
核心:Java的protected权限有严格的访问范围限制
很多人对protected的理解存在误区,以为“子类能访问父类的protected成员,那外部类通过子类实例也能访问”,但实际上Java对protected的访问规则是:
protected成员仅能被以下场景访问:
- 声明该成员的类本身(比如
Powers类内部可以访问所有成员) - 与声明类同一个包的所有类(如果有类在
first.second包,不管是不是子类都能访问eleventh) - 不同包的子类,但必须是在子类的代码内部,通过子类自身的实例(比如
this,或者子类方法内创建的子类对象)访问继承来的protected成员
对应你的代码场景逐一分析
SuperPowers类中能访问eleventh的原因
SuperPowers是Powers的子类,且访问操作是在自己的方法printPowers内部:this.eleventh:子类通过自身实例访问继承的protected成员,符合规则sp.eleventh:在子类方法内创建子类实例并访问,同样属于子类内部通过子类实例访问,符合规则
所以这两种写法都合法。
TestPowers类中无法直接访问sp.eleventh的原因
TestPowers既不是Powers的子类(即使让它继承Powers,它和Powers也不在同一个包),也和Powers分属不同包。此时TestPowers属于“外部类”,哪怕拿到SuperPowers的实例,也没有权限直接访问该实例从父类继承的protected成员——protected权限并没有开放给“非子类+不同包”的类,哪怕这个类和子类同包也不行。即使TestPowers继承Powers也无效的原因
如果TestPowers继承Powers,那么TestPowers自己的代码里可以用this.eleventh,或者在TestPowers的方法里创建TestPowers实例访问eleventh,但依然不能通过SuperPowers实例访问eleventh。因为protected权限只允许子类访问自己继承的那一份protected成员,不能跨子类访问其他子类实例中的protected成员——哪怕两个子类同包也不允许。
总结
protected的核心逻辑是:只有子类自身的代码内部,才能访问自己继承来的protected成员;外部类哪怕和子类同包,也不能通过子类实例直接访问父类的protected成员。
内容的提问来源于stack exchange,提问作者Christian

