为什么在同一个包中看不到包保护方法?
假设我们有两个包p1
和p2
以及由p2.M12
扩展的类p2.M12
,如下所示:
package p1; public class M1 { void method1() { System.out.println("Method 1 called"); } } package p2; import p1.M1; public class M12 extends M1 { void method2() { System.out.println("Method 2 called"); } }
让我们用p2.B
扩展M12
:
package p2; public class B extends M12 { public void doSomething() { method1(); method2(); } }
这给出了一个编译错误,因为method1
在p1
被包保护在p2
不可见。 method2
可见而没有问题。
现在让我们用p1.A
扩展p1.A
:
package p1; import p2.M12; public class A extends M12 { public void doSomething() { method1(); method2(); } }
这里我得到了method2()
(可以理解) 和 method1()
的编译错误:
我的问题是:为什么在包p1
受包保护的method1
在同一个包p1
的类A
是不可见的?
首先,什么是class级成员? Java语言规范说明
类主体可以包含类成员的声明,即字段(第8.3节),方法(第8.4节),类(第8.5节)和接口(第8.5节)。
他们是由什么组成的? JLS表示
类类型的成员都是以下所有成员:
- 成员inheritance自其直接超类 (第8.1.4节),但类Object中没有直接超类
- 成员inheritance自任何直接的超级接口(第8.1.5节)
- 在class级正文中宣布的成员(§8.1.6)
它也提到了
只有声明为
protected
或public
的类的成员才会被声明在声明类之外的包中声明的子类inheritance。
所有这些都在关于inheritance的章节中进行了重写
类
C
从其直接超类inheritance超类的所有具体方法m
(静态和实例),以下所有条件都为真:
m
是C
的直接超类的成员。m
是与C`在同一个包中的public
,protected
或声明的包访问 。- 在
C
中声明的方法没有签名是m
的签名的子签名(第8.4.2节)。
M1
类的成员是method1
(以及Object
所有方法)。 M12
与其直接超类M1
,不会inheritance方法1。 因此, M12
的成员只是方法2。
B
的直接超类是M12
并且在同一个包中。 因此它inheritance了其成员method2
。 B
对method1
一无所知。 如果您使用javac
编译了代码,则会收到cannot find symbol
编译错误的错误。 (似乎Eclipse试图猜测你想要做什么。)
类似地, A
的直接超类是M12
,但是在不同的包中。 由于这个原因,它不inheritancemethod2
。 A
对method1
或method2
一无所知,因为它没有inheritance它们。 这两个都是无法找到的符号。
我认为理解这种行为的最简单方法是“A是M12”的想法
当您声明inheritance时,您告诉A从M12获取其行为,但是M12没有名为method1的可见方法。
让我们做一个有趣的实验:
public class M12 extends p1.M1 { public void method1() { System.out.println("Method 1 called"); } void method2() { System.out.println("Method 2 called"); } }
忘记A ..当你声明这样的方法时,它是允许的 – 如果你没有@Override。 但是,如果M1是:
public class M1 { public void method1() { System.out.println("Method 1 called"); } }
你可以有:
public class M12 extends p1.M1 { @Override public void method1() { System.out.println("Method 1 called"); } void method2() { System.out.println("Method 2 called"); } }
现在,回到M1和M2的原始代码,重新声明方法,方法一公开:
public class M12 extends p1.M1 { public void method1() { System.out.println("Method 1 called"); } public void method2() { System.out.println("Method 2 called"); } }
然后,你就可以拥有
public class A extends M12 { public void doSomething() { method1(); method2(); } }
好吧,这是一个微不足道的案例,但是缺少完成序列…底线,从语义上讲,你可以通过IS关系来解释。
如果需要更多( https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html ):
下表显示了每个修饰符允许的成员访问权限。
访问级别
Modifier Class Package Subclass World public YYYY protected YYYN no modifier YYNN private YNNN
可见性必须流经类层次结构。
类层次结构是A --> M12 --> M1
从M12
看M1.method1
,它对它的任何子类都不可见,就像A
一样。