Java、Javac、Javadoc查詢class路徑總結
這兩天在用Eclipse編譯檔案的時候遇到些class無法找到的問題,於是想重新學習java查詢class的機制。本文內容參考官方文件Java Tuturial How Classes are Found和Setting the Class Path。
1、Java載入類
Java 按照載入順序將類分為三種:引導類、擴充套件類和使用者類,分別依次載入。
- 引導類是如rt.jar等共同構成Java平臺的關鍵Jar檔案
- 擴充套件類是通過Java擴充套件機制建立的Jar檔案,位於$JAVA_HOME/jre/lib/ext
- 使用者類是開發者或第三方未按照Java擴充套件機制建立的類(大部分情況屬於此)
引導類與擴充套件類一般不必設定載入路徑,所以本文重點討論使用者類。
注意: tools.jar現在必須在包含在使用者類路徑中,否則無法使用。
使用者類路徑設定
使用者類在使用時必須引用使用者類路徑(user class path),以完成後綴為jar、class、zip的類檔案的引用。使用者類路徑有以下幾種設定方式:
- 預設值 . 表示當前編輯檔案路徑。(不必設定,只要當前編輯路徑下的同包或非包類檔案都可以自動載入)
- CLASSPATH環境變數可以覆蓋前者,這個就不多說了,Linux和Windows系統環境變數設定在網上都可以查到。
- -cp/-classpath選項
- -jar選項 這個比較特殊,在該選項下,所有使用的類必須包含在該jar檔案中。
下面詳細說下 -cp選項 設定要點。
-cp選項可以在不更改環境變數的情況下配置使用者類查詢路徑。jar檔案、zip檔案和class檔案設定方法不盡相同。
- jar檔案或zip檔案 路徑必須以檔名結尾,如需引用當前目錄下mydir資料夾下的myclass.jar檔案,則命令為 java -cp ./mydir/myclass xx。
- 非包class檔案 路徑必須為包含該類檔案的資料夾路徑,如需引用當前目錄下mydir資料夾下的myclass.class,則命令為 java -cp ./mydir xx。
- 包class檔案 路徑必須為該包的根目錄,如該包為online.sanbao,則命令為 java -cp ./online xx
2、Javac和Javadoc載入類
Javac和Javadoc以相似的方式載入類,不過有以下幾點不同:
- 如果在類檔案和原始檔中均定義了引用的類,javadoc總是使用原始檔而javac使用類檔案,但根據既定規則自動重新編譯它認為過時的任何類檔案。自動重新編譯的規則記錄在用於Windows或Unix的javac文件中。
- 預設情況下,javac和javadoc會在使用者類路徑下查詢待載入的原始檔和類檔案。但如果指定了-sourcepath選項,javac和javadoc僅在指定的原始檔路徑上搜索原始檔,而在使用者類路徑中搜索類檔案。
3、舉例說明
本機CLASSPATH變數設定如圖1,主要包括.(當前編輯目錄)、dt.jar檔案、tools.jar檔案和/root/workspace(工作目錄)四個類路徑。
情況一:當兩個檔案都是非包且位於同一個資料夾下
首先,在test目錄下建立Test.java和myclass.java檔案,如圖2所示。
Test.java 內容如下:
public class Test{
public static void main(String[] args){
Myclass myclass = new Myclass();
System.out.println("本例用來測試使用者類是否試著成功。");
}
}
Myclass.java內容如下:
public class Myclass{
Myclass(){
System.out.println("這是一個Myclass例項。");
}
}
執行結果如圖3所示:
簡單分析:當執行 javac Test.java 時,由於沒有-cp和-sourcepath選項,此時CLASSPATH變數生效,javac依次在CLASSPATH變數所指的路徑查詢Myclass類和原始碼,因此在當前目錄(找到Myclass會不會停止查詢有待考證)下找到Myclass原始碼,但並未找到Myclass類,於是分別對Test.java和Myclass.java檔案進行編譯,生成Myclass.class和Test.class檔案,這裡有個細節,仔細檢視Myclass.class和Test.class檔案修改時間可以發現,先生成Test.java然後生成Myclass.class,這點是和C++不同的地方。然後java依據相同邏輯查詢類並執行。
情況二:當非包檔案屬於兩個不同資料夾
首先,在當前目錄下建立子資料夾 subDirectory,然後將Myclass.java移動至該子資料夾。
有兩種解決方案:一是利用設定-cp選項,這樣可以指定classpath,類似情況一,具體如圖4。
注意:-cp選項下,對於.class檔案需選擇該檔案所在資料夾,不包含檔名;另外,在執行java命令時,需指明所有類路徑,包括當前路徑和Myclass.class檔案所在路徑。
二是java名稱空間查詢class路徑。
此時,如果直接用javac編譯會提示錯誤,如圖5所示。因為這違反了java關於名稱空間的規則,在不使用-cp選項的情況下,若想引用其他資料夾的類,必須使用package/import規則。
因此,修改Myclass.java檔案和Test.java檔案。
//定義包名;
package subDirectory;
public class Myclass{
//注意修改建構函式許可權為public,因為已屬於不同的包;
public Myclass(){
System.out.println("這是Myclass的一個例項。");
}
}
import subDirectory.Myclass;
public class Test{
public static void main(String[] args){
Myclass myclass = new Myclass();
System.out.println("本例用來測試使用者類是否試著成功。");
}
}
再次執行結果如圖6。