Java編程思想__訪問權限控制

  • 訪問控制( 或隱藏具體實現 )與最初的實現並不恰當 有關。
  • Java提供了訪問修飾詞,以供類庫開發人員向客戶端程序員指明那些是可用的,那些是不可用的。訪問權限控制的等級,從最大權限到最小的權限依次爲: public , protected , 包訪問權限(沒有關鍵詞)private

 

包: 庫單元

  • 包內包含一組類,它們在單一的名字空間之下被組織在了一起。
public class SimpleEnumUse {
    public static void main(String[] args) {
        java.util.ArrayList arrayList=new  java.util.ArrayList();
    }

}
  1. 這立刻使程序變得很冗長,因此 你可能想轉試用 import 關鍵字。如下
import java.util.ArrayList;

public class SimpleEnumUse {
    public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();
    }
}
  1. 現在可以不用限定地使用 ArrayList了,但是, 這樣做 java.util 中的其他類仍舊是都不可用的。要想導入其中所有的類,只需使用 * ,如下
import java.util.*;
  1. 我們之所以要導入, 就是要提供一個管理名字空間的機制。所有類成員的名稱都是批次隔離的。
  2. 在Java中對名稱空間進行完全控制併爲每個類創建唯一的標識符組合就成爲了非常重要的事情。

 

代碼組織

  • Java可運行程序是一組可以打包並壓縮爲一個Java文檔文件(JAR ,使用Java的jar文檔生成器)的 .class 文件。Java解釋器負責這些文件的查找,裝載 和解釋。
  • 類庫實際上是一組類文件。 其中每個文件都有一個 public 類,以及任意數量的非public 類, 因此每個文件都有一個構件。這就要使用 package 
//如果使用 package 它必須處於 文件中除註釋以外第一句程序代碼
package access;
  1. 就表示你在聲明該編譯單元是名爲 access 的類庫的一部分。或者換句話說,你正在聲明該編譯單元中的public 類名稱是位於 access 名稱的保護傘下。
  2. 任何想要使用該名稱的人都必須使用前面給出的選擇,指定全名或者與 access 結合使用關鍵字 import。
  3. package 和 import關鍵字允許你做的,是將單一的全局名字空間分隔開,使得無論多少人使用 Internet以及 Java開始編寫類, 都不會出現名稱衝突問題。

 

創建獨一無二的包名

  • 將所有的文件收入一個子目錄還可以解決另外兩個問題:
  1. 通過將 .class 文件所在的路徑位置編碼成 package 的名稱來實現,也就是 反順序自己的Internet域名
  2. 把package 名稱分解爲你機器上的一個目錄。當Java程序運行並需要加載 .class 文件的時候,它就可以確定 .class 文件在目錄上所處的位置。
  • Java解釋器運行過程:
  • 找出環境變量 CLASSPATH ,CLASSPATH包含一個或者多個目錄,用作查找 .class文件的根目錄。從根目錄開始,解釋器獲取包的名稱並將每個句點替換爲反斜槓,以從 CLASSPATH 根中產生一個路徑名稱。得到的路徑會與CLASSPATH 中的各個不同的項相連接, 解釋器就在這些目錄中查找與你所要創建的類名稱相關的 .class 文件。

 

用 Import 改變行爲

  • Java 沒有C的條件編譯功能,該功能可以使你不必要更改任何程序代碼,就能夠切換開關併產生不同的行爲。
  • 條件編譯還有一些有價值的用途。調試就是一個很常見的用途。調試功能在開發過程中是開啓的,而在發佈的產品中是禁用的。可以通過修改被導入的 package 的方法來實現這一目的,修改的方法是將你程序中用到的代碼從調試版改爲發佈版本。

 

 

對使用包的忠告

  • 無論何時創建包,都必須在給定包的時候隱含地指定了目錄結構。
  • 注意: 編譯過的代碼通常放置在與源代碼的不同目錄中,但是必須保證 JVM 使用 CLASSPATH 可以找到該路徑。

 

Java 訪問權限修飾詞

  • public , protected 和 private 這幾個Java訪問權限修飾詞在使用時,是置於類中每個成員的定義之前的__無論它是一個域還是一個方法。每個訪問權限修飾詞僅控制它所修飾的特定定義的訪問權。
  • 如果不提供任何訪問權限修飾詞,則意味着它是 包訪問權限 。因此,無論何時,所有事物都具有某種形式的訪問權限控制。

 

包訪問權限

  • 默認訪問權限沒有任何關鍵字,但通常是指包訪問權限(有時也表示爲 friendly)。這就意味着當前的包中的所有其他類對成員都有訪問權限,但對於這個包之外的所有類,這個成員卻是 private。由於一個編譯單元(即一個文件),只能隸屬於一個包,所以經由包訪問權限,處於同一編譯單元中的所有類彼此之間都是自動可訪問的。
  • 在Java中,則要強制你以一種合理的方式對它們加以組織。另外,你可能還想要排除這樣的類__它們不應該訪問在當前包中所定義的類。

 

public : 接口訪問權限

  • 使用關鍵字 public :就意味着 public 之後緊跟着的成員聲明自己對每個人都是可用的,尤其是使用類庫的客戶程序員更是如此。
package com.spring.main.demo;

public class SimpleEnumUse {

    public SimpleEnumUse(){
        System.out.println("SimpleEnumUse 構造器");
    }

    void bite(){
        System.out.println("bite");
    }
}
  1. SimpleEnumUse.java 文件必須處於 demo的子目錄中,該子目錄在 com.spring.main下, 而c05 則必須位於 CLASSPATH指定的衆多路徑的其中之一的下邊。
//創建一個 SimpleEnumUse 對象
import com.spring.main.demo.*;

public class Dinner {

    public static void main(String[] args) {
        SimpleEnumUse enumUse = new SimpleEnumUse();
        //enumUse.bite();    無法訪問
    }
}


//運行結果爲
SimpleEnumUse 構造器
  1. 就可以創建一個 SimpleEnumUse對象,因爲它的構造器是 public 而且類也是 public的。但是, 由於 bite()只向 demo 包中的類提供訪問權,所以 bite()成員在 Dinner之中是無法訪問的,因此編譯器也禁止你使用它。

 

 

默認包

  • 下面程序代碼看起來破壞了上述規則,但它仍可以編譯:
package com.access;

class Pie {
    void f(){
        System.out.println("Pie f()方法");
    }
    
}

//第二個類
package com.access;

class Cake {
    public static void main(String[] args) {
        Pie pie = new Pie();
        pie.f();
    }
}

//運行結果爲
Pie f()方法
  1. 最初或許你認爲這倆個文件毫不相關,但是 Cake卻可以創建一個 Pie對象並調用它的 f()方法, 通常會認爲 Pie 和 f() 享有包訪問權限,因而是不可以爲 Cake所用的。
  2. 它們的確享有包訪問權限,但這只是部分正確的。Cake.java 可以訪問它們的原因是因爲它們同處於相同的目錄並且沒有給自己設定任何包名稱。
  3. Java將這樣的文件自動看做隸屬於該目錄的默認包之中,於是它們爲該目錄中所有其他的文件都提供了包訪問權限。

 

 

private: 你無法訪問

  • private: 除了包內該成員的類之外,其他任何類都無法訪問這個成員。由於處於同一包內的其他類是不可以訪問 private成員的,因此這就等於說自己隔離了自己。
  • 從另一方面來說,讓許多人共同合作來創建一個包也是不大可能的,爲此 private 就允許你隨意改變該成員,而不必考慮這樣做是否會影響到包內其他的類。
  • 默認包訪問權限已經提供了充足的隱藏措施。請記住,使用類的客戶端程序員是無法訪問包訪問權限成員的
package com.access;

class Pie {
    
    private Pie(){}
    
    static Pie createObject(){
        return new Pie();
    }
}


//第二個測試類
package com.access;

class Cake {
    public static void main(String[] args) {
        Pie pie = Pie.createObject();
        // Pie pie = new Pie();
    }
}

  1. 這是一個說明 private 終有用武之地的示例, 可能想控制如何創建對象,並阻止別人直接訪問某個特定的構造器(或全部構造器)。
  2. 在例子中,不能通過構造器來創建 Pie 對象,而必須調用 createObjet方法來達到此目的。
  • 任何可以肯定只是該類一個助手方法的方法,都可以把它定爲 private,確保不會再包內的其他地方誤用到它,於是也就防止了你會去改變或刪除這個方法。將方法指定爲 private 確保了你擁有這種選擇權。
  • 對於類中的 private 域同樣適用。除非必須全部公開底層實現細目,否則就應該將所有的域指定爲 private

 

protected: 集成訪問權限

  • protected : 通過繼承可以利用一個現有類__我們將其稱爲基類,然後將新成員添加到該現有類中而不必碰該現有類。
  • 還可以改變現有成員的行爲。爲了從現有類繼承,需要聲明新類 extends (擴展)了一個現有類,如下
class Foo extends Bar{}
  • 類定義中的其他部分看起來都是一樣的。
package com.access;

public class Pie {

    public Pie(){
        System.out.println("pie構造器已經執行");
    }

    protected void createObject(){
        System.out.println("createObject");
    }
}

//第二個類

package com.access;

public class Cake extends Pie{

    public Cake(){
        System.out.println("Cake container");
    }

    public void chomp(){
        createObject();
    }

    public static void main(String[] args) {
        Cake cake = new Cake();
        cake.chomp();
    }
}

//運行結果
pie構造器已經執行
Cake container
createObject
  1. 儘管 createObject()也具有包訪問權限,但是它仍舊不是 public的。

 

 

接口和實現

  • 訪問權限的控制常被稱爲 具體實現的隱藏
  • 把數據 和方法 包裝進類中,以及具體實現的隱藏,常共同稱作 封裝。其結果是一個同時帶有特徵和行爲的數據類型。
  • 出於兩個很重要的原因,訪問權限控制將權限的邊界劃在了數據類型的內部。
  1. 是要設定客戶端程序員可以使用和不可以使用的界限。可以在結構中建立自己的內部機制,而不必擔心客戶端程序員會偶然地將內部機制當做它們可以使用的接口的一部分。
  2. 即將接口和具體實現進行分離。如果結構是用於一組程序之中,而客戶端程序員除了可以向接口發送信息之外也不可以做的話,那麼就可以隨意更改所有不是public 的東西,從而破壞客戶端代碼。

 

類的訪問權限

  • 在Java中,訪問權限修飾詞也可以用於確定庫中的那些類對於該庫的使用者是可用的。
public class Widget{}
//如果庫的名字是 access 那麼任何客戶端程序員都可以通過下面的聲明訪問 Widght
import access.Widget;
//或者
import access.*;
  1. 每個編譯單元(文件)都只能有一個 public 類。每個編譯單元都有單一的公共接口,用 public 類來表現。
  2. public類的名稱必須完全與含有編譯單元的文件名想匹配,包括大小寫。所以對於 Widget而言,文件的名稱必須是 Widget.java而不是 widget.java 或者 WIDGET.java 。如果不匹配,同樣將得到編譯時錯誤。
  3. 雖然不是很常用,但編譯單元內完全不帶 public 類也是可能的。在這種情況下,可以隨意對文件命名。
  • 請注意 : 類不可以是 private 的,也不可以是 protected的
  • 所以對於類的訪問權限,僅有倆個選擇 :包訪問權限public 

 

總結

  • 本章討論了類是如何被構建成類庫的:首先,介紹了一組類是如何被打包到一個類庫中的,其次,類是如何控制其成員的訪問的。
  • 控制對成員的訪問權限有兩個原因:
  1. 爲了使用戶不要碰觸那些他們不該碰觸的部分,這些部分對於類內部的操作是必要的,但是它並不屬於客戶端程序員所需接口的一部分。
  2. 爲了讓類庫設計者可以更改類的內部工作方式,而不必擔心這樣會對客戶端程序員產生重大的影響。
  • 注意:
  • 訪問權限控制專注於類庫創建這和該類庫的外部使用者之間的關係,這種關係也是一種通信方式。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章