Java中的權限修飾符(protected)示例詳解
前言
大部分來自:https://blog.csdn.net/justloveyou_/article/details/61672133。並在這個博客的基礎上,加上瞭自己的一些理解。
權限控制表
修飾詞 | 本類 | 同一個包的類 | 繼承類 | 其他類 |
---|---|---|---|---|
private | √ | × | × | × |
無(默認) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
關於protected
最近在看Effective Java時,遇到瞭一個關於protected
修飾符的問題。這個問題中,對於它的認識與我之前對它的認識有一些出入。所以在這裡記錄一下。
很多介紹Java語言的書籍(包括《Java編程思想》)都對protected介紹的比較的簡單,基本都是一句話,就是:被protected修飾的成員對於本包和其子類可見。這種說法有點太過含糊,常常會對大傢造成誤解。實際上,protected的可見性在於兩點:
- 父類的protected成員是包內可見的,並且對子類可見;
- 若子類與父類不在同一包中,那麼在子類中,子類實例可以訪問其從父類繼承而來的protected方法,而不能訪問父類實例的protected方法。
在碰到涉及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方法。
為什麼要這樣以及這樣要如何解釋呢?
我想這可能需要思考一下對子類可見的定義。先加一個構造函數,在這個構造函數裡面,可以訪問clone方法,這個方法來自MyObject2
。
所以,再寫一個類Test22繼承自MyObject2,然後重新寫個方法testSuperClone()
,如下:
感覺這兩個之間還是存在一些差距。所以,我的不太恰當理解為:對子類的實例可見,即可以在子類中,通過子類的實例去訪問相應的protected方法。
示例三
p3/MyObject3.java
package basic.testprotected.p3; import basic.testprotected.p33.Test3; public class MyObject3 extends Test3 {}
p33/Test3.java
對於(1)而言,clone()方法來自於類Test3,因此其可見性為包p33及其子類MyObject3,而(1)正是在p33的類Test3中調用,屬於同一包,編譯通過。
示例四
p4/MyObject4.java
package basic.testprotected.p4; import basic.testprotected.p44.Test4; public class MyObject4 extends Test4 { protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
p44/Test4.java
對於(1)而言,clone()方法來自於類MyObject4,因此其可見性為包p4及其子類(此處沒有子類),而類Test4卻在包p44中,因此不滿足可見性,編譯不通過。
示例五
p5/MyObject5.java
package basic.testprotected.p5; public class MyObject5 { protected Object clone() throws CloneNotSupportedException{ return super.clone(); } }
p5/Test5.java
對於(1)而言,clone()方法來自於類MyObject5,因此其可見性為包p5及其子類(此處沒有子類),而類Test5也在包p5中,因此滿足可見性,編譯通過。
示例六
package p6; class MyObject6 extends Test6{} public class Test6 { public static void main(String[] args) { MyObject6 obj = new MyObject6(); obj.clone(); // Compile OK -------(1) } }
對於(1)而言,clone()方法來自於類Test6,因此其可見性為包p6及其子類MyObject6,而類Test6也在包p6中,因此滿足可見性,編譯通過。
示例七
package p7; class MyObject7 extends Test7 { public static void main(String[] args) { Test7 test = new Test7(); test.clone(); // Compile Error ----- (1) } } public class Test7 { }
對於(1)而言,clone()方法來自於類Object,因此該clone()方法可見性為包java.lang及其子類Test7,由於類MyObject7不在此范圍內,因此不滿足可見性,編譯不通過。
總結
到此這篇關於Java中權限修飾符(protected)的文章就介紹到這瞭,更多相關Java權限修飾符(protected)內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java設計模式之java原型模式詳解
- Java 中的 clone( ) 和 new哪個效率更高
- Java中 ? extends T 和 ? super T的理解
- 詳解Java深拷貝,淺拷貝和Cloneable接口
- Java抽象類和接口使用梳理