1. 程式人生 > >Java程式設計思想(六)—— 訪問許可權控制

Java程式設計思想(六)—— 訪問許可權控制

一、包:庫單元

        包內含有一組類,它們在單一的名字空間下被組織在了一起。例如,在Java的標準釋出中有一個工具庫,它被組織在java.util名字空間下,如果要使用此名字空間下的ArrayList類,可以使用其命名的方式,如下:

public static void main(String[] args) {
        java.util.List<String> stringList = new java.util.ArrayList<>();
    }

        但這樣就把程式變得的冗餘太多了,為了簡化程式碼則可以使用import關鍵字來匯入某個包下的類,使用import的方式,如下:

import java.util.ArrayList;
import java.util.List;

public class ImportPackageDemo {

    void example1(){
        List<String> stringList = new ArrayList<>();
    }

}

        如果要匯入該包下的很多類,則可以使用萬用字元*來代替類名,即:import java.util.*

1、程式碼組織

        當編寫一個Java原始碼檔案時,此檔案通常被稱為編譯單元,每一個編譯單元都必須要有一個字尾名.java,而在編譯單元內則可以有一個public類,該類的名稱必須與檔案的名稱相同(不包括字尾),每一個編譯單元只能有一個public類,否則編譯器就不會接受。如果該編譯單元之中還有其他類的話,那麼你只能在包內訪問它,在包之外的世界是看不到這些類的,因此它們不是public類,它們只是為public類提供支援的一些類。

        當編譯一個.java檔案時,在.java檔案中的每個類都會有一個輸出檔案,而該輸出檔案的名稱與.java檔案中的每個類的檔案相同,只是多了一個字尾名.class,因此,在編譯少量.java檔案之後,會出現大量的.class檔案。Java可執行程式是一組可以打包並壓縮為一個Java文件檔案的.class檔案。Java直譯器負責這些檔案的查詢、裝載和解釋。

        類庫實際上是一組類檔案,其中每個檔案都有一個public類,以及任意數量的非public類。因此,每個檔案都有一個構件,如果希望這些構件從屬於同一個群組或者單元,就可以使用關鍵字package。如果使用package語句,它必須是檔案中除註釋以外的第一句程式程式碼。示例如下:

package com.thinkinjava.chapter6;

public class ImportPackageDemo {

}

2、獨一無二的包名與CLASSPATH

        使用package和import的目的,是為了將單一的全域性名字空間分割開來,以免很多一起編寫程式時出現名稱衝突問題。按照慣例,package名稱的第一部分是類的建立者的反順序的Internet域名,然後是專案名或模組名以及其他識別符號,按照這樣的慣例,你就可以建立獨一無二的包名了。

        Java直譯器的執行過程是:首先,找出環境變數CLASSPATH,CLASSPATH包含一個或多個目錄,用作查詢.class檔案的根目錄。從根目錄開始,直譯器獲取包的名稱並將每個句點替換成反斜槓,以從CLASSPATH中產生一個路徑名稱(如com.mengfei.test就變成了com\mengfei\test或com/mengfei/test)。得到的路徑會與CLASSPATH中的名個不同的項相連線,直譯器就在這些目錄中查詢與你所要建立的類名稱相關的.class檔案。

        下面示例CLASSPATH的使用方法。

⑴ 對於沒有使用package的情況

首先,在E盤建立一個Java目錄,然後在Java目錄下建立一個Demo.java檔案,檔案中的原始碼如下:

public class Demo
{
	public static void main(String[] args){
		System.out.println("Hello World");
	}
}

        使用cmd命令,開啟DOS視窗進入到Java目錄, 使用javac Demo.java進行編譯,然後再使用java Demo執行class檔案,如下:

        我們沒有設定CLASSPATH,但是執行成功,這是因為CLASSPATH預設為當前路徑,如果我們到E盤的根目錄下執行相同的命令則會報:找不到或無法載入主類的錯誤,如下:

        這時如果我們想在E盤的根目錄下也可以執行Demo.class檔案則需要設定CLASSPATH,有三種方式,示例如下:

① 設定CLASSPATH臨時變數,作用只限於當前DOS命令視窗,視窗關閉失效

② 在使用命令時新增CLASSPATH引數,作用只限於當前執行class檔案的命令

③ 在系統環境變數中加入CLASSPATH,永久有效

設定地址:我的電腦 → 屬性 → 高階系統設定 → 環境變數 → 新建,然後輸入變數名和變數值

 ⑵ 對於使用了package的情況

        我們先在類檔案中新增一行打包的程式碼,即:

package test;

         然後在DOS視窗執行javac -d Demo.java命令,注意:使用了package進行編譯時,要在命令中加上-d .引數,目的是告訴編譯器要在當前目錄下自動生成與包同名的資料夾,並把類檔案放到該資料夾下面。否則JVM無法在包資料夾下找到要載入的類檔案。示例如下:

        如果這時設定CLASSPATH並在根目錄下執行相同的命令,結果是一樣的,如下:

二、Java訪問許可權修飾詞

        public、protected、private這幾個許可權訪問修飾詞是置於類中每個成員定義之前的,每個訪問許可權修飾詞僅控制它所修飾的特定定義的訪問權。如果不提供任何訪問許可權修飾詞,則意味著它是包訪問許可權。如下圖所示:

三、介面和實現

        訪問許可權的控制通常被稱為是具體實現的隱藏,把資料和方法包裝進類中,以及具體實現的隱藏,一起被稱為封裝。其結果是一個同時帶有特徵和行為的資料型別。訪問許可權控制將許可權的邊界劃在了資料型別的內部,主要原因有兩點:

① 是要設定客戶端程式設計師可以使用和不可以使用的界限。開發者可以在結構中建立自己的內部機制,而不必擔心客戶端程式設計師會偶然地將內部機制當作是他們可以使用的介面的一部分;

② 將介面和具體實現進行分離。客戶端程式設計師除了可以向介面傳送訊息之外什麼也不可以做,這樣就可以更改所有不是public的東西,而不會破壞客戶端程式碼。

四、類的訪問許可權

        對於類的許可權只可使用包訪問許可權(即預設)或者public(內部類除外,它是一個特例),如果不希望其他人對該類擁有訪問許可權,則可以把所有的構造器都指定為private,從而阻止其他人建立該類的物件,但此時你依然可以在靜態成員方法建立該類的物件,然後你可以決定是否將該方法置為public。

        示例一:設定私有的構造方法,用靜態成員方法返回類的例項,如下

public class VisitPermission {
    public static void main(String[] args) {
        Demo1 demo1 = Demo1.getInstance();
        demo1.printSomething();
        //列印結果:Hello Demo1
    }
}

class Demo1{
    private Demo1(){}

    public static Demo1 getInstance(){
        return new Demo1();
    }

    public void printSomething(){
        System.out.println("Hello Demo1");
    }
}

        示例二:設定私有構造方法,用靜態資料成員初始化類的例項,實現餓漢式單例模式,如下:

public class VisitPermission {
    public static void main(String[] args) {
        Demo2 demo2 = Demo2.getInstance();
        demo2.printSomething();
        //列印結果:Hello Demo2
    }
}

class Demo2{
    private Demo2(){}
    
    private static Demo2 demo2 = new Demo2();

    //由於靜態資料成員只會初始化一次,所以這個方法返回的是類的單例,也就是說這個類永遠只有一個例項
    public static Demo2 getInstance(){
        return demo2;
    }

    public void printSomething(){
        System.out.println("Hello Demo2");
    }
}