跨包继承时Java的protected与package-private可见性疑惑
Java可见性规则:两个困惑案例的解析
先明确核心规则的准确表述,避免误解:
- package-private(默认可见性):仅允许同一个包内的类直接访问该成员,与继承关系无关;如果子类和父类不同包,子类无法继承也无法访问父类的package-private成员。
- protected:包含两层权限:
- 同包内的任何类(无论是否继承)都可以访问该成员;
- 不同包的子类,仅能访问自身实例或自身子类实例中继承来的protected成员。
第一个案例:为什么能访问ChildOtherPackage实例的protectedField?
你的代码:
package thisPackage; import otherPackage.ChildOtherPackage; public class GrandChild extends ChildOtherPackage { public void test (ChildOtherPackage c) { System.out.println(c.protectedField); // 可正常运行 } }
关键原因:GrandChild与Parent在同一个包(thisPackage)。根据protected的第一条规则,同包内的类无需依赖继承关系,就能直接访问Parent的protected成员——不管是Parent实例、ChildOtherPackage实例还是GrandChild实例,只要是Parent的子类实例,GrandChild作为同包类都有权限访问其protectedField。你之前误以为是跨包子类的访问规则在起作用,但实际上这里触发的是同包访问权限,优先级更高。
第二个案例:为什么访问GrandChild实例的packagePrivateField会报错?
你的代码:
package thisPackage; import otherPackage.ChildOtherPackage; public class GrandChild extends ChildOtherPackage { public void test (GrandChild g) { System.out.println(g.packagePrivateField); // 编译报错 } }
报错的核心逻辑:
- Parent的
packagePrivateField是默认可见性,仅允许thisPackage内的类直接访问; - GrandChild虽然在thisPackage,但它是通过
ChildOtherPackage(otherPackage中的类)继承Parent的。而ChildOtherPackage与Parent不同包,无法访问Parent的packagePrivateField,因此ChildOtherPackage根本没有继承这个字段; - 当GrandChild尝试访问
g.packagePrivateField时,编译器会沿着继承链(GrandChild → ChildOtherPackage → Parent)查找,发现Parent有该字段,但由于中间的ChildOtherPackage无访问权限,GrandChild无法通过继承链获取该字段的访问权; - 注意:如果GrandChild直接继承Parent(而非ChildOtherPackage),那么它作为同包子类,是可以访问自身实例的packagePrivateField的——但这里的继承链跨了包,阻断了权限传递。
补充验证
如果把GrandChild改成直接继承Parent,以下代码就能正常运行:
package thisPackage; public class GrandChildDirect extends Parent { public void test(GrandChildDirect g) { System.out.println(g.packagePrivateField); // 正常运行,因为同包+直接继承 } }
内容的提问来源于stack exchange,提问作者Daniel Hidalgo Chica
相关产品推荐
相关产品推荐

