跨包子类访问父类protected字段的权限差异问题解析
Java中protected访问权限的规则解析
先看涉及的核心代码:
父类代码(test1.visibility包)
package test1.visibility; public class Test { private int privateField = 1; int defaultField = 2; protected int protectedField = 3; }
子类代码(test2.visibility包)
package test2.visibility; import test1.visibility.Test; public class ExtendsTestOutsideThePackage extends Test { public static void main(String[] args) { Test tt = new Test(); Test te = new ExtendsTestOutsideThePackage(); ExtendsTestOutsideThePackage ee = new ExtendsTestOutsideThePackage(); // 以下为关键代码行 System.out.println(tt.protectedField); //compilation error System.out.println(te.protectedField); //compilation error System.out.println(ee.protectedField); //works fine } }
针对三个关键代码行的解释
要搞清楚原因,得先明确Java中protected权限的核心规则:不同包的子类只能通过自身类型的引用访问父类的protected成员,不能通过父类类型的引用访问,也不能直接访问父类的实例。
- 第1行报错原因:
tt是父类Test的直接实例,当前类和Test分属不同包。protected权限并没有赋予外部包类直接访问父类实例成员的权利,所以编译报错。 - 第2行报错原因:
te的引用类型是父类Test,虽然实际对象是子类ExtendsTestOutsideThePackage,但Java的访问权限检查是基于引用类型而非实际对象类型的。因为引用类型是不同包的父类,所以无法访问protected成员。 - 第3行正常运行原因:
ee的引用类型是子类ExtendsTestOutsideThePackage,也就是当前类本身。作为不同包的子类,Java允许通过自身类型的引用访问父类的protected成员,所以代码可以正常编译运行。
总结
- 不同包下,不能直接通过父类实例访问protected成员(对应tt的情况)。
- 哪怕实际对象是子类,只要引用类型是父类,不同包下也无法访问protected成员(对应te的情况)。
- 只有通过子类自身类型的引用,不同包的子类才能访问父类的protected成员(对应ee的情况)。
内容的提问来源于stack exchange,提问作者iwsnmw
相关产品推荐
相关产品推荐

