摘要
在Java中,使用访问权限修饰符来保护对类、变量、方法和构造方法的访问,这类修饰符分别是public,protected,default,以及private。由于很多Java书籍对protected可见性的介绍都比较笼统,本文重点说明protected的权限
一、Java权限访问修饰符
各访问修饰符权限如下:
同一个类中 | 同一个包内 | 不同包的子类 | 不同包的其他类 | |
public | ✔ | ✔ | ✔ | ✔ |
protected | ✔ | ✔ | ✔* | |
default | ✔ | ✔ | ||
private | ✔ |
在上面所提到的四种修饰词中,除 protected 外都很好理解和掌握,在此略作简述:
- public :能被所有的类访问。
- default :只能被同一包中的类访问。
- private :只能在定义它的类中被访问,其他类都访问不到。
二、protected关键字的可见性
很多介绍Java语言的书籍(比如《Java编程思想》)都对protected做了介绍,但是描述的比较简单,基本都是一句话“被protected修饰的成员对于本包和其子类可见”。这种说法有点太过含糊,常常会对大家造成误解。实际上,protected的可见性在于以下几点:
- 基类的protected成员在同一个包内可见。
- 若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。
- 不管是否在一个包中,在基类,都可以通过子类实例访问继承的来自父类的protected方法。
- 若子类与基类不在同一包中,那么在基类中,不能通过子类实例访问(父类中没有)子类中特有的protected修饰的成员。
接下来我们通过下面几个关于protected方法可见性的例子进行详细解释protected关键字:
示例一:
package p1;public class Father1 { protected void f() {} // 父类Father1中的protected方法}package p1;public class Son1 extends Father1 {}package p11;public class Son11 extends Father1{}package p1;public class Test1 { public static void main(String[] args) { Son1 son1 = new Son1(); son1.f(); // Compile OK ----(1) son1.clone(); // Compile Error ----(2) Son11 son = new Son11(); son11.f(); // Compile OK ----(3) son11.clone(); // Compile Error ----(4) }}
- 首先看(1) (3),其中f()方法从类Father1继承而来,其可见性是包p1及其子类Son1和Son11,而由于调用f()方法的类Test1所在的包也是p1,同一个包内可见,因此(1)(3)处编译通过。
- 其次看(2) (4),其中clone()方法所在类为Object默认根类,而Object类所在包为java.lang包。其可见性是java.lang包及其所有子类,对于语句“son1.clone();”和“son11.clone();”,二者的clone()在类Son1、Son2中是可见的(可以使用的),但在Test类是不可见的,因此(1)(3)处编译不通过
示例二:
package p2;public class Father2 { protected Object clone() throws CloneNotSupportedException{ return super.clone(); }}package p22;import p2.Father2;public class Son2 extends Father2 { public static void main(String args[]) throws CloneNotSupportedException { Father2 f2 = new Father2(); f2.clone(); // Compile Error ----(1) Son2 son2 = new Son2(); son2.clone(); // Complie OK ----(2) }}
- 对于(1)而言,clone()方法来自于类Father2本身,因此其可见性为包p2及Father2的子类,虽然Son2是Father2的子类,但在Son2中不能访问基类Father2的protected方法clone(),因此编译不通过;
- 对于(2)而言,由于在Son2中访问的是其本身实例的从基类Father2继承来的的clone(),因此编译通过。
示例三:
package p3;import p33.Son3;public class Father3 { public static void main(String[] argv) throws CloneNotSupportedException { Son3 son3 = new Son3(); son3.clone(); // Compile OK ------(1) }}package p33;import p3.Father3;public class Son3 extends Father3 {}
- 不管是否在同一个包中,在基类中,可以通过子类实例访问继承的来自基类的protected方法。(当然,基类clone()方法,也是继承自java.lang.Object))
示例四:
package p4;import p44.Son4;public class Father4 { public static void main(String[] argv){ Son4 son4 = new Son4(); son4.clone(); // Compile Error -----(1) }}package p44;import p4.Father4;public class Son4 extends Father4 { protected Object clone() throws CloneNotSupportedException { return super.clone(); }}
- 在基类中,不能通过子类实例访问(基类中没有)子类中特有的protected修饰的成员。
示例五:
package p5;public class Father5 { protected Object clone() throws CloneNotSupportedException{ return super.clone(); }}package p5;public class Test5 { public static void main(String[] args) throws CloneNotSupportedException { Father5 f5 = new Father5(); f5.clone(); // Compile OK ----(1) }}
- clone() 方法来自类Father5,其可见性为包p5 及其子类。
示例六:
package p6;public class Father6 { public static void main(String[] args) throws CloneNotSupportedException { Son6 son6 = new Son6(); son6.clone(); // Compile OK -------(1) }}class Son6 extends Father6{}
- 不管是否在同一个包中,在基类中,可以通过子类实例访问继承的来自基类的protected方法。(当然,父类clone()方法,也是继承自java.lang.Object))
示例七:
package p7;public class Father7 {}class Son7 extends Father7{ public static void main(String[] args){ Father7 f7 = new Father7(); f7.clone(); // Compile Error ----- (1) }}
- clone方法来自于java.lang.Object,可见性为java.lang这个包和对应继承了这个clone()方法的子类,及Father7类中。
三、引用
来源地址:https://blog.csdn.net/zhangx_developer/article/details/130421720