Java 中的权限修饰符(protected)
大部分来自 protected 加了一些自己的理解
权限控制表
在学到cloned方法时,看到这样一句话
Object类中的clone方法声明为protected,所以你的代码不能直接调用anObject.clone()。但是,不是所有的子类都可以访问受保护的方法吗?不是所以的类都是Object的子类吗?辛运的是,受保护访问的规则比较微妙。子类只能调用受保护的clone方法来克隆它自己的对象。必须重新定义clone为public才能允许所有方法可隆对象。
我在想这话说的不是很对的,不是所有类都是Object的子类吗,为什么还要声明为protected呢,在查阅相关资料后,我得出了一些结论。
首先要了解protected的真正访问权限
1.父类的protected 方法的可见性是同包内和子类
2.若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法,而不能访父类实例的protected方法。
第一句话好理解,但对于第二句话你可能不知道在说什么,且不急,继续往下看,你就会明白。
示例一
p1/Father1.java
package basic.testprotected.p1;
public class Father1 {
protected void f() {} // 父类Father1中的protected方法
}
p1/Son1.java
package basic.testprotected.p1;
public class Son1 extends Father1{}
p11/Son11.java
package basic.testprotected.p11;
import basic.testprotected.p1.Father1;
public class Son11 extends Father1{}
p1/Test1.java
首先看(1)(3),其中的f()方法从类Father1继承而来,其可见性是包p1及其子类Son1和Son11,而由于调用f()方法的类Test1所在的包也是p1,因此(1)(3)处编译通过。也就是说,如果我们换一个包,比如Test11.java在p11下,那么将都不可访问。如下:
其次看(2)(4),其中的clone()方法的可见性是java.lang包及其所有子类,对于语句son1.clone();和son11.clone();,二者的clone()在类Son1、Son11中是可见的,但对Test1是不可见的,因此(1)(3)处编译不通过。也就是说,如果在Son1或Son11这两个类中调用clone()方法,则是可以编译通过的。
示例二
p2/MyObject2.java
package basic.testprotected.p2;
public class MyObject2 {
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
p22/Test2.java
对于(1)而言,clone()方法来自于类MyObject2本身,因此其可见性为包p2及MyObject2的子类,虽然Test2是MyObject2的子类,但在Test2中不能访问父类MyObject2的protected方法clone(),因此编译不通过; 对于(2)而言,由于在Test2中访问的是其本身实例的从父类MyObject2继承来的的clone(),因此编译通过。所以在这里,就很好地阐述了上面所给的第二条结论:
若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法,而不能访问父类实例的protected方法。
为什么要这样以及这样要如何解释呢?
至此我们得出在子类中只能通过子类实例克隆本子类对象,而不能克隆其他子类对象(实现了Cloneable接口,重写clone方法的子类对象除外)
因此我们剖析了protected的访问权限,也可以很容易理解为什么clone方法为什么要声明成protected
clone写成protected的真正原因是设计者希望子类只能调用保护的clone方法克隆他自己的对象,而不能克隆其他对象,但子类可能存在需要深拷贝或不可拷贝的字段,但不能保证子类的设计者一定会修正clone方法让其正常工作,处于安全性考虑,在Object类中将其声明为protected,这也是为什么要进行深拷贝时要改protected为public,此时就可以clone其他对象了