Java访问指示符 访问修饰符
5.2 Java訪問指示符
針對類內每個成員的每個定義,Java訪問指示符poublic,protected以及private都置于它們的最前面——無論它們是一個數據成員,還是一個方法。每個訪問指示符都只控制著對那個特定定義的訪問。這與C++存在著顯著不同。在C++中,訪問指示符控制著它后面的所有定義,直到又一個訪問指示符加入為止。
通過千絲萬縷的聯系,程序為所有東西都指定了某種形式的訪問。在后面的小節里,大家要學習與各類訪問有關的所有知識。首次從默認訪問開始。
5.2.1 “友好的”
如果根本不指定訪問指示符,就象本章之前的所有例子那樣,這時會出現什么情況呢?默認的訪問沒有關鍵字,但它通常稱為“友好”(Friendly)訪問。這意味著當前包內的其他所有類都能訪問“友好的”成員,但對包外的所有類來說,這些成員卻是“私有”(Private)的,外界不得訪問。由于一個編譯單元(一個文件)只能從屬于單個包,所以單個編譯單元內的所有類相互間都是自動“友好”的。因此,我們也說友好元素擁有“包訪問”權限。
友好訪問允許我們將相關的類都組合到一個包里,使它們相互間方便地進行溝通。將類組合到一個包內以后(這樣便允許友好成員的相互訪問,亦即讓它們“交朋友”),我們便“擁有”了那個包內的代碼。只有我們已經擁有的代碼才能友好地訪問自己擁有的其他代碼。我們可認為友好訪問使類在一個包內的組合顯得有意義,或者說前者是后者的原因。在許多語言中,我們在文件內組織定義的方式往往顯得有些牽強。但在Java中,卻強制用一種頗有意義的形式進行組織。除此以外,我們有時可能想排除一些類,不想讓它們訪問當前包內定義的類。
對于任何關系,一個非常重要的問題是“誰能訪問我們的‘私有’或private代碼”。類控制著哪些代碼能夠訪問自己的成員。沒有任何秘訣可以“闖入”。另一個包內推薦可以聲明一個新類,然后說:“嗨,我是Bob的朋友!”,并指望看到Bob的“protected”(受到保護的)、友好的以及“private”(私有)的成員。為獲得對一個訪問權限,唯一的方法就是:
(1) 使成員成為“public”(公共的)。這樣所有人從任何地方都可以訪問它。
(2) 變成一個“友好”成員,方法是舍棄所有訪問指示符,并將其類置于相同的包內。這樣一來,其他類就可以訪問成員。
(3) 正如以后引入“繼承”概念后大家會知道的那樣,一個繼承的類既可以訪問一個protected成員,也可以訪問一個public成員(但不可訪問private成員)。只有在兩個類位于相同的包內時,它才可以訪問友好成員。但現在不必關心這方面的問題。
(4) 提供“訪問器/變化器”方法(亦稱為“獲取/設置”方法),以便讀取和修改值。這是OOP環境中最正規的一種方法,也是Java Beans的基礎——具體情況會在第13章介紹。
5.2.2 public:接口訪問
使用public關鍵字時,它意味著緊隨在public后面的成員聲明適用于所有人,特別是適用于使用庫的客戶程序員。假定我們定義了一個名為dessert的包,其中包含下述單元(若執行該程序時遇到困難,請參考第3章3.1.2小節“賦值”):
//: Cookie.java // Creates a library package c05.dessert;public class Cookie {public Cookie() { System.out.println("Cookie constructor"); }void foo() { System.out.println("foo"); } } ///:~請記住,Cookie.java必須駐留在名為dessert的一個子目錄內,而這個子目錄又必須位于由CLASSPATH指定的C05目錄下面(C05代表本書的第5章)。不要錯誤地以為Java無論如何都會將當前目錄作為搜索的起點看待。如果不將一個“.”作為CLASSPATH的一部分使用,Java就不會考慮當前目錄。 現在,假若創建使用了Cookie的一個程序,如下所示:
//: Dinner.java // Uses the library import c05.dessert.*;public class Dinner {public Dinner() {System.out.println("Dinner constructor");}public static void main(String[] args) {Cookie x = new Cookie();//! x.foo(); // Can't access} } ///:~就可以創建一個Cookie對象,因為它的構建器是public的,而且類也是public的(公共類的概念稍后還會進行更詳細的講述)。然而,foo()成員不可在Dinner.java內訪問,因為foo()只有在dessert包內才是“友好”的。
大家可能會驚訝地發現下面這些代碼得以順利編譯——盡管它看起來似乎已違背了規則:
//: Cake.java // Accesses a class in a separate // compilation unit.class Cake {public static void main(String[] args) {Pie x = new Pie();x.f();} } ///:~在位于相同目錄的第二個文件里:
//: Pie.java // The other classclass Pie {void f() { System.out.println("Pie.f()"); } } ///:~最初可能會把它們看作完全不相干的文件,然而Cake能創建一個Pie對象,并能調用它的f()方法!通常的想法會認為Pie和f()是“友好的”,所以不適用于Cake。它們確實是友好的——這部分結論非常正確。但它們之所以仍能在Cake.java中使用,是由于它們位于相同的目錄中,而且沒有明確的包名。Java把象這樣的文件看作那個目錄“默認包”的一部分,所以它們對于目錄內的其他文件來說是“友好”的。
5.2.3 private:不能接觸!
private關鍵字意味著除非那個特定的類,而且從那個類的方法里,否則沒有人能訪問那個成員。同一個包內的其他成員不能訪問private成員,這使其顯得似乎將類與我們自己都隔離起來。另一方面,也不能由幾個合作的人創建一個包。所以private允許我們自由地改變那個成員,同時毋需關心它是否會影響同一個包內的另一個類。默認的“友好”包訪問通常已經是一種適當的隱藏方法;請記住,對于包的用戶來說,是不能訪問一個“友好”成員的。這種效果往往能令人滿意,因為默認訪問是我們通常采用的方法。對于希望變成public(公共)的成員,我們通常明確地指出,令其可由客戶程序員自由調用。而且作為一個結果,最開始的時候通常會認為自己不必頻繁使用private關鍵字,因為完全可以在不用它的前提下發布自己的代碼(這與C++是個鮮明的對比)。然而,隨著學習的深入,大家就會發現private仍然有非常重要的用途,特別是在涉及多線程處理的時候(詳情見第14章)。 下面是應用了private的一個例子:
//: IceCream.java // Demonstrates "private" keywordclass Sundae {private Sundae() {}static Sundae makeASundae() { return new Sundae(); } }public class IceCream {public static void main(String[] args) {//! Sundae x = new Sundae();Sundae x = Sundae.makeASundae();} } ///:~這個例子向我們證明了使用private的方便:有時可能想控制對象的創建方式,并防止有人直接訪問一個特定的構建器(或者所有構建器)。在上面的例子中,我們不可通過它的構建器創建一個Sundae對象;相反,必須調用makeASundae()方法來實現(注釋③)。
③:此時還會產生另一個影響:由于默認構建器是唯一獲得定義的,而且它的屬性是private,所以可防止對這個類的繼承(這是第6章要重點講述的主題)。
若確定一個類只有一個“助手”方法,那么對于任何方法來說,都可以把它們設為private,從而保證自己不會誤在包內其他地方使用它,防止自己更改或刪除方法。將一個方法的屬性設為private后,可保證自己一直保持這一選項(然而,若一個句柄被設為private,并不表明其他對象不能擁有指向同一個對象的public句柄。有關“別名”的問題將在第12章詳述)。
5.2.4 protected:“友好的一種”
protected(受到保護的)訪問指示符要求大家提前有所認識。首先應注意這樣一個事實:為繼續學習本書一直到繼承那一章之前的內容,并不一定需要先理解本小節的內容。但為了保持內容的完整,這兒仍然要對此進行簡要說明,并提供相關的例子。
protected關鍵字為我們引入了一種名為“繼承”的概念,它以現有的類為基礎,并在其中加入新的成員,同時不會對現有的類產生影響——我們將這種現有的類稱為“基礎類”或者“基本類”(Base Class)。亦可改變那個類現有成員的行為。對于從一個現有類的繼承,我們說自己的新類“擴展”(extends)了那個現有的類。如下所示:
class Foo extends Bar {類定義剩余的部分看起來是完全相同的。
若新建一個包,并從另一個包內的某個類里繼承,則唯一能夠訪問的成員就是原來那個包的public成員。當然,如果在相同的包里進行繼承,那么繼承獲得的包能夠訪問所有“友好”的成員。有些時候,基礎類的創建者喜歡提供一個特殊的成員,并允許訪問衍生類。這正是protected的工作。若往回引用5.2.2小節“public:接口訪問”的那個Cookie.java文件,則下面這個類就不能訪問“友好”的成員:
//: ChocolateChip.java // Can't access friendly member // in another class import c05.dessert.*;public class ChocolateChip extends Cookie {public ChocolateChip() {System.out.println("ChocolateChip constructor");}public static void main(String[] args) {ChocolateChip x = new ChocolateChip();//! x.foo(); // Can't access foo} } ///:~對于繼承,值得注意的一件有趣的事情是倘若方法foo()存在于類Cookie中,那么它也會存在于從Cookie繼承的所有類中。但由于foo()在外部的包里是“友好”的,所以我們不能使用它。當然,亦可將其變成public。但這樣一來,由于所有人都能自由訪問它,所以可能并非我們所希望的局面。若象下面這樣修改類Cookie:
public class Cookie {public Cookie() { System.out.println("Cookie constructor");}protected void foo() {System.out.println("foo"); } }那么仍然能在包dessert里“友好”地訪問foo(),但從Cookie繼承的其他東西亦可自由地訪問它。然而,它并非公共的(public)。
from:?https://quanke.gitbooks.io/think-in-java/content/5.2%20Java%E8%AE%BF%E9%97%AE%E6%8C%87%E7%A4%BA%E7%AC%A6.html
總結
以上是生活随笔為你收集整理的Java访问指示符 访问修饰符的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java IO最详解
- 下一篇: 趣文:如果网络浏览器是妹纸