关于外部类不能用 protected 修饰及子类访问不同包父类的 protected 成员 的一点思考
所谓访问权限控制符的作用,通俗点理解就是:控制它的作用域或者说控制可见范围。
简单的说就是:
private : 只有本包内可见,
默认(default): 只有同一包内可见
protected : 同一包内以及子类中可见
public : 任何地方都可见
问题:
一问:外部类为什么不能用 protected 修饰?
答:外部类的上一级程序单元是包,所以它只有 2 个作用域:同一个包内和任何位置。因此只需要
2 种访问权限:包访问权限和可公开访问权限,也正好对应了:省略访问控制符 和 public访问控制符。
省略访问控制符 是包权限,即同一包中其他类可以访问。也就是说它只在这个包内是可见的,在其他包内是不可见的。
protected 权限是除了本包,还多了子类可访问。但对于外部类来说,只要不是用 public 修饰,在其他包中都是不可见的,而在其他包中不可见也就无从说继承了。所以实际效果跟 省略访问控制符的效果是一样的,也就没必要用 protected 。
二问:子类如何访问不同包的父类的 protected 成员?
答:子类访问父类的 protected 成员实际上并不是 创建一个父类对象,然后用这个对象调用访问。而是用自己的实例对象访问自己的从父类那里继承来的
protected 的成员。
这么说有点绕,还可以这样说:子类访问的是自己的 protected 成员,只是这个 protected 成员是从父类哪里继承来的。
示例代码:
父类 Father
package p1;
public class Father {
// 定义一个 protected 修饰的实例变量
protected int a = 5;
// 定义一个 protected 修饰的方法
protected void test(){
System.out.println("父类的 protected 修饰的普通方法 test()");
}
// 定义一个 protected 修饰的内部类
protected class InnerClass {
// Attention please: 构造器的修饰符默认是和类一样的,并不都是默认就是 public
// 所以,默认构造器实际上是 protected InnerClass(){}
// 在这里将构造器改为 public 修饰,以便于在其他包的外部类子类中创建实例
public InnerClass() {}
}
}
子类 Son
package p2;
import p1.Father;
public class Son extends Father {
public static void main(String[] args) {
// 分别创建一个父类和子类实例
Father f = new Father();
Son s = new Son();
// 用父类对象调用它的 protected 成员
//System.out.println(f.a); // 编译错误
//f.test(); // 通不过编译
InnerClass fi = f.new InnerClass();// 可以通过编译,因为内部类的构造器已改为 public 修饰
// 用子类对象调用继承来的 protected 对象
System.out.println(s.a);
s.test();
InnerClass si = s.new InnerClass();
}
}
运行结果:
END