使用 protected 访问控制符
这是基础内容了,但是不能轻视,越基础越要清晰理解。
Protected Access
这是用于演示 protected 关键字的代码包图。


首先创建一个 Bird 类并将其成员设置为 protected :
1
2
3
4
5
6
7
package pond.shore;
public class Bird {
protected String text = "floating"; // protected 访问
protected void floatInWater() { // protected 访问
System.out.println(text);
}
}
接着我们创建一个子类:
1
2
3
4
5
6
7
8
package pond.goose;
import pond.shore.Bird; // 在不同的包
public class Gosling extends Bird { // 创建子类
public void swim() {
floatInWater(); // 调用 protected 成员
System.out.println(text); // 调用 protected 成员
}
}
运行以上代码,会打印 floating 两次,一次因为调用 floatInWater() 另一次因为 swim() 里面的 println()。 因为 Gosling 是 Bird 的子类,它可以访问这些成员,即使不在同一个包。 记住 protected 允许所有默认访问权限所允许的。(Remember protected also gives us access to everything that default access does.) 意味着与 Bird 在同一个包的类可以访问它的 protected 成员。
1
2
3
4
5
6
7
8
package pond.shore; // 与 Bird 在同一个包
public class BirdWatcher {
public void watchBird() {
Bird bird = new Bird();
bird.floatInWater(); // 调用 protected 成员
System.out.println(bird.text); // 调用 protected 成员
}
}
现在我们尝试在不同的包做同样的操作:
1
2
3
4
5
6
7
8
package pond.inland; // 与 Bird 不在同一个包
public class BirdWatcherFromAfar {
public void watchBird() {
Bird bird = new Bird();
bird.floatInWater(); // 不能通过编译
System.out.println(bird.text); // 不能通过编译
}
}
BirdWatcherFromAfar 与 Bird 不在同一个包,且不是 Bird 的子类,所以无法访问 Bird 的 protected 成员。
好了,现在看看下面这个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package pond.swan;
import pond.shore.Bird; // 与 Bird 不在同一个包
public class Swan extends Bird { // 但是 Bird 的子类
public void swim() {
floatInWater(); // 包访问父类
System.out.println(text); // 包访问父类
}
public void helpOtherSwanSwim() {
Swan other = new Swan();
other.floatInWater(); // 包访问父类
System.out.println(other.text); // 包访问父类
}
public void helpOtherBirdSwim() {
Bird other = new Bird();
other.floatInWater(); // 不能通过编译
System.out.println(other.text); // 不能通过编译
}
}
上面代码,helpOtherBirdSwim() 方法里面 other.floatInWater() 和 System.out.println(other.text) 不能通过编译是因为引用变量 other 的类型是 Bird。 如果通过引用变量访问一个成员,能否访问取决于引用的变量的类型。
再看看下面这个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package pond.goose;
import pond.shore.Bird;
public class Goose extends Bird {
public void helpGooseSwim() {
Goose other = new Goose();
other.floatInWater();
System.out.println(other.text);
}
public void helpOtherGooseSwim() {
Bird other = new Goose();
other.floatInWater(); // 不能通过编译
System.out.println(other.text); // 不能通过编译
}
}
上面代码中,在第二个方法 helpOtherGooseSwim() 有问题,尽管创建的是一个 Goose 对象,但是 other 保存的引用类型是 Bird。因为 Goose 与 Bird 不在同一个包,而且 Bird 不是 Goose 的子类,所以不允许访问 Bird 的成员。
在看多一个例子:
1
2
3
4
5
6
7
8
package pond.duck;
import pond.goose.Goose;
public class GooseWatcher {
public void watch() {
Goose goose = new Goose();
goose.floatInWater(); // 不能通过编译
}
}
代码不能通过编译的原因是我们不在 Goose 类里面。 floatInWater() 方法是 Bird 类中声明的。 GooseWatcher 与 Bird 不在同一个包,而且不是 Bird 的子类。Goose 继承自 Bird 只是允许 Goose 访问 floatInWater() ,而不是 Goose 的调用者。