假设我们有p1
和p2
两个包,p1.M1
扩展了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");
}
}
让M12
与p2.B
一起展开:
package p2;
public class B extends M12 {
public void doSomething() {
method1();
method2();
}
}
这会导致编译错误为method1
,p1
内的包受保护在p2
中不可见。 method2
可以毫无问题地显示出来。
现在让p2.M12
与p1.A
一起展开:
package p1;
import p2.M12;
public class A extends M12 {
public void doSomething() {
method1();
method2();
}
}
我在method2()
(这是可以理解的)和 method1()
获得了编译错误:
我的问题是:为什么包method1
中受包保护的p1
在同一个包A
的类p1
中不可见?< / p>
答案 0 :(得分:3)
我认为理解这种行为的最简单方法是“A是M12”的想法
当您声明继承时,您告诉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 Y Y Y Y
protected Y Y Y N
no modifier Y Y N N
private Y N N N
答案 1 :(得分:2)
首先,什么是班级成员? Java Language Specification州
一个类体可能包含该类成员的声明 是,字段(§8.3),方法(§8.4),类(§8.5)和接口 (第8.5节)。
他们是由什么组成的? JLS states
类类型的成员都是以下所有:
- 直接超类(第8.1.4节)中继承的成员,但在没有直接超类的类Object中除外
- 从任何直接超接口继承的成员(第8.1.5节)
- 会员在课堂正文中宣布(§8.1.6)
它还提到了
只有声明为
protected
或public
的类的成员才是 继承自在包中声明的包中声明的子类 该类被宣布。
所有这些都改编在chapter on Inheritance
中班级
C
继承自直接超类所有具体方法m
(超静态和实例)所有的超类 以下是真实的:
- 的直接超类的成员
m
是C
。m
是public
,protected
或在与C` 相同的包中声明包裹访问权。C
中声明的方法没有签名是m
签名的子签名(第8.4.2节)。
班级M1
的成员是method1
(以及Object
的所有方法)。 M12
与其直接超类M1
位于不同的包中,不会继承method1
。因此,M12
的成员仅为method2
。
B
的直接超类是M12
,并且位于同一个包中。因此它继承了其成员method2
。 B
对method1
一无所知。如果您使用javac
编译了代码,则会收到cannot find symbol
编译错误。 (似乎Eclipse试图猜测你想要做什么。)
同样,A
的直接超类是M12
,但是在不同的包中。由于这个原因,它不会继承method2
。 A
对method1
或method2
一无所知,因为它没有继承它们。这两个都是无法找到的符号。
答案 2 :(得分:1)
可见性必须流经类层次结构。
类层次结构为A --> M12 --> M1
自M1.method1
以来M12
不可见,它的任何子类都不可见,例如A
。