完全掌握java中的"包"機制

完全掌握java中的"包"機制

作者:陳健明    來自:SUN

 

"包"機制是java中特有的,也是java中最基礎的知識。一些初學java的朋友,通常象學其它語言一樣從教材上copy一些程序來運行,可是卻常常遇到莫名其妙的錯誤提示。這些問題事實上都出在對"包"的原理不夠清楚。本文將就此問題進行深入闡述。

一、爲什麼java中要有"包"的概念?

以一言概之,java中"包"的引入的主要原因是java本身跨平臺特性的需求。因爲java中的所有的資源也是以文件方式組織,這其中主要包含大量的類文件需要組織管理。java中同樣採用了目錄樹形結構。雖然各種常見操作系統平臺對文件的管理都是以目錄樹的形式的組織,但是它們對目錄的分隔表達方式不同,爲了區別於各種平臺,java中採用了"."來分隔目錄。

二、java中包結構和平臺的銜接

java中的資源存在於不同平臺下時必然會有很大差異。因此跨平臺的java包結構和平臺之間必須通過一種方式來銜接到一起。事實上它們就是通過我們很熟悉的classpath的設置來銜接到一起的。舉個例子:

我在Windows2000環境下的classpath設置如下:

classpath = d:/jdk1.4.2/lib/dt.jar; d:/cjm

類的銜接關係可以用下圖來表達:

從圖中可以看出,java中的類的組織是"懸空"的,這樣的話,它們可以隨意放在任意平臺下,但是要在該平臺下正確找到一個類,則必須使用classpath來設置類所在目錄的前面一部分(即區別於平臺的部分)。在java中常常把一棵類樹壓縮成一個.jar文件,如圖中的rt.jar,這並不影響對類的查找,在指定環境變量時可以指定.jar文件所在目錄,也可以具體指明.jar的完全查找路徑,即上例中的classpath中也可描述成:

classpath = d:/jdk1.4.2/lib; d:/cjm

當正確設置了平臺下的classpath環境變量時,java跨平臺的特性就體現出來了。即你在編寫程序中,描述一個類時,就不用具體指明它的完整路徑,而是僅僅指明java中的類路徑就可以了,即指出圖1中豎線右邊的查找路徑就可以了。這樣的話,你編寫的程序拿到任何平臺下時,只需要根據類文件的存放目錄來書寫相應的classpath環境變量,而不用因爲類的存放環境變化而修改程序。

注意:java中對於某個類的查找是把classpath中的每一項逐一連接,當一個連接能夠正確找到相關類後,便不再向後查找。

三、正確使用"包"

在使用包的過程中有很多需要注意的小細節,這裏把常見的問題都列舉如下:

1、對類路徑的設置通常有兩種方法:

i)在系統的環境變量中設置,設置方法依據平臺而變;

ii)以命令參數的形式來設置。

如:javac -classpath d:/jdk1.4.2/lib d:/cjm/edu/test/TestFile.java
java -classpath .;d:/jdk1.4.2/lib; d:/cjm  edu.test.TestFile

注意:i)javac和java命令有很大區別,可以這樣區分,javac是一個平臺命令,它對具體的平臺文件進行操作,要指明被編譯的文件路徑。而java是一個虛擬機命令,它對類操作,即對類的描述要用點分的描述形式,並且不能加擴展名,還要注意類名的大小寫。

ii)有一個很奇怪的問題,即javac命令後面的classpath默認包含當前目錄(符合windows的習慣),可是在java命令後面的classpath卻不包含當前目錄,所以在它的classpath中一定不能忘了加上當前目錄的描述,即加上"."。

2、在java程序中對類路徑的描述用"."分隔,而且也有當前目錄的概念。如要運行圖1中的TestFile必須指明爲 edu.test.TestFile。但是如果在類TestFile中要調用和它在同一目錄中的TestString,則不必指明目錄前綴。

3、在java程序中所有使用到的類都應該清楚的指明這個類的查找路徑。一般有兩種方法指明:

i)在程序的開始使用import關鍵字指明。如類TestFile中要用到FileInputStream類,則在程序頭中加入import java.io.FileReader; 或import java.io.*;

ii)在程序中用到FileFileReader類處直接寫完整路徑,如: java.io.FileFileReader fin = new java.io.FileReader("filename");

注意:java.lang包總是被默認導入的。

4、類的目錄結構一定要和類中第一句"包聲明"一致。如類TestFile.class對應的.java文件的第一句必須包含:package edu.test;

確保類的存放路徑和類中指明的"包路徑"一致的方法一般有兩種:

i)編寫.java文件時存放的目錄事先確定好,如TestFile.java就直接放在edu/test目錄下,然後用下面的語句編譯:

javac  -classpath d:/jdk1.4.2/lib d:/cjm/edu/test/TestFile.java
當編譯完成後,產生的TestFile.class文件會出現在編譯命令中java文件的描述路徑中。即出現在d:/test/edu/test中

ii)通過-d參數的使用來編譯程序。如使用下面的語句來編譯:

javac  -d  d:/cjm  d:/temp/TestFile.java
將在-d後指定的目錄d:/cjm下面自動按照packagek中指定的目錄結構來創建目錄,並且將產生的.class文件放在這個新建的目錄下,即在d:/cjm下面建立/edu/test目錄,然後產生的TestFile.class放在d:/cjm/edu/test目錄下。

5、爲了便於工程發佈,可以將自己的類樹打成.jar文件。如將圖1中的edu下面的所有類文件打成一個.jar文件,可以先轉到d:/cjm目錄,再用下面的命令:

  jar -cvf test.jar edu/
這時會在d:/test下產生一個test.jar文件,此.jar文件中包含edu/下的完整目錄結構和文件。使用這個.jar文件時,只需在classpath中指明.jar文件的存放路徑即可。

6、對其它資源的使用,如圖標文件,文本等資源文件的使用必須要注意,查找資源文件不應從類文件所在的目錄開始,而是應該從package指定的類路徑的起點開始(圖1中從edu所在目錄開始)。如圖1中看到的文本文件word.txt在resource下面,而類文件TestFile.class在edu/test下,在TestFile.class中要使用到resource中的word.txt,要按如下操作:

fin= new FileReader("resource/word.txt");
而不應該是:fin= new FileReader("../../resource/word.txt");

四、舉例

本例用於統計一個文本文件中的單詞數,註釋中的編號對應前一節的編號:

// TestFile.java
package edu.test; // --------------------------------------- 4
import java.io.FileReader; // ------------------------------ 3
import java.io.LineNumberReader;
class TestFile{
    public static void main(String []argv){
        TestString ts = new TestString(); // ---------------- 2
        FileReader fin;
        LineNumberReader line = null;
        int wordNum = 0;
        try{
            fin= new FileReader("resource/word.txt"); // ---- 6
            line = new LineNumberReader(fin);   
        }catch(Exception e){
            e.printStackTrace();
            System.exit(0);
        }
        while(true){
            try{
                String temp = line.readLine();
                wordNum += ts.CountWord(temp);
            }catch(Exception e){
                break;
            }
        }
        try{
            line.close();
        }catch(Exception e){};
        System.out.println("Word count is:" + wordNum);
    }
}


// TestString.java
package edu.test;
import java.util.*;
class TestString {
    int CountWord(String str){
        StringTokenizer token = new StringTokenizer(str);
        return token.countTokens();
    }
}

兩個.java文件存放在d:/temp目錄下,當前目錄爲d:/temp使用下面的命令進行編譯:

d:/temp>javac  -classpath d:/jdk1.4.2/lib  -d d:/test  *.java

用下面的命令運行:

// --------------------------------- 1
d:/temp> java -classpath .;d:/jdk1.4.2/lib; d:/test/com  edu.test.TestFile

如果需要打包的話,先轉到d:/test,然後用下面命令:

// --------------------------------- 5
jar -cvf test.jar edu/

這時可產生一個test.jar文件,可將此文件置於任何平臺下使用。

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