其實這個問題,就是一句話,那就是“與基類不在同一個包中的子類,只能訪問自身從基類繼承而來的受保護的成員,而不能訪問基類執行個體本身的受保護的成員”。
原創作品,允許轉載,轉載時請務必以超連結形式標明文章 原始出處 、作者資訊和本聲明。否則將追究法律責任。http://zhangjunhd.blog.51cto.com/113473/19287
本文分析一下protected
存取權限。author: ZJ 2007-3-5Blog: [url]http://zhangjunhd.blog.51cto.com/[/url] 來談談protected存取權限問題。看下面樣本1:Test.java
| class MyObject {} public class Test { public static void main(String[] args) { MyObject obj = new MyObject(); obj.clone(); // Compile error. }} |
此時出現上文提到的錯誤:The method clone from the type Object is not visiuable.我們已經清楚Object.clone()是protected方法。這說明,該方法可以被同包(java.lang)下和它(java.lang.Object)的子類訪問。這裡是MyObject類(預設繼承java.lang.Object)。同樣Test也是java.lang.Object的子類。但是,不能在一個子類中訪問另一個子類的protected方法,儘管這兩個子類繼承自同一個父類。再看樣本2:Test2.java
| class MyObject2 { protected Object clone() throws CloneNotSupportedException { return super.clone(); }} public class Test2 { public static void main(String[] args) throws CloneNotSupportedException { MyObject2 obj = new MyObject2(); obj.clone(); // Compile OK. }} |
這裡,我們在MyObject2類中覆蓋(override)父類的clone()方法,在另一個類Test2中調用clone()方法,編譯通過。編譯通過的原因顯而易見,當你在MyObject2類中覆蓋clone()方法時,MyObject2類和Test2類在同一個包下,所以此protected方法對Test2類可見。分析到這裡,我們在回憶一下Java中的淺複製與深複製文中,章節2.2中的聲明,
②
在衍生類別中覆蓋基類的clone()
方法,並聲明為public
。現在明白這句話的原因了吧(為了讓其它類能調用這個類的clone()方法,重載之後要把clone()方法的屬性設定為public)。下面再來看樣本3:Test3.java
| package 1class MyObject3 {protected Object clone() throws CloneNotSupportedException { return super.clone(); }} package 2public class Test3 extends MyObject3 { public static void main(String args[]) { MyObject3 obj = new MyObject3(); obj.clone(); // Compile error. Test3 tobj = new Test3(); tobj.clone();// Complie OK. }} |
這裡我用Test3類繼承MyObject3,注意這兩個類是不同包的,否則就是樣本2的情形。在Test3類中調用Test3類的執行個體tobj的clone()方法,編譯通過。而同樣調用MyObject3類的執行個體obj的clone()方法,編譯錯誤!意想不到的結果,protected方法不是可以被繼承類訪問嗎?必須明確,類Test3確實是繼承了類MyObject3(包括它的clone方法),所以在類Test3中可以調用自己的clone方法。但類MyObject3的protected方法對其不同包子類Test3來說,是不可見的。對於樣本1的解釋就是——雖然MyObject與Test屬於同一個包,但受保護的clone方法來自java.lang.Object類型,而在Test中,其基類Object的受保護方法是不可見的。
對於樣本2的解釋就是——MyObject與Test在同一個包中,受保護的clone方法來自MyObject本身,所以它對Test而言是可見的。另外在這個樣本中,還說明了super關鍵字對於基類受保護的成員的調用是個語言設計之中的“例外”。
樣本3很簡單了,就是企圖跨越不同的包,從子類中調用基類執行個體的受保護方法。
最後,我在補充兩個例子:
樣本4:(針對樣本1的修改)
class MyObject extends Test{}
public class Test {
public static void main(String[] args) {
MyObject obj = new MyObject();
obj.clone(); // Compile ok.
}
}
為什麼可見呢?因為MyObject的clone方法繼承自Test,而Test做為相對於Object的子類,是可以訪問繼承而來的屬於它自己的受保護方法的~
樣本5:
package 1
class MyObject extends Test {
}
package 2
public class Test {
public static void main(String args[]) {
MyObject obj = new MyObject();
obj.clone(); // Compile OK
}
}
雖然處於不同的包,但子類的受保護方法實際上繼承自父類,父類的自己的受保護方法對自己可見,其原理同樣本4.
樣本6:
package 1
class MyObject extends Test {
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package 2
public class Test {
public static void main(String args[]) {
MyObject obj = new MyObject();
obj.clone(); // Compile error!
}
}
不同包中子類本身的受保護方法當然不可能對父類可見~
再補充樣本7:
package a;
class MyObject extends Test {
public static void main(String[] args) {
Test test = new Test();
test.clone(); // Compile error.
}
}
package a;
public class Test {
}
同一個包中,父類執行個體的clone方法在子類中依然不可見,原理同樣本1,就是因為父類的clone方法,實際上來自java.lang.Object