《Java從入門到失業》第四章:類和對象(4.6):類路徑
- 2020 年 9 月 25 日
- 筆記
- 《Java從入門到失業》, Java從入門到失業
4.6類路徑
4.6.1什麼是類路徑
前面我們討論過包,知道位元組碼文件最終都會被放到和包名相匹配的樹狀結構子目錄中。例如上一節的例子:
其實類還有一種存放方式,就是可以歸檔到一個jar文件中,jar文件其實就是把位元組碼文件連同子目錄一同歸檔到一個壓縮文件中。jar文件是使用zip格式壓縮的,我們可以使用zip程式來查看和解壓jar文件。其實Java自帶的類庫就是jar文件。例如JRE安裝目錄jre/lib和jre/lib/ext下就有很多jar。我們看一下jre/lib/rt.jar的結構:
我們看到,無論是單獨存放還是歸檔jar,都有一個基目錄(黑色部分),上面2個圖的基目錄分別為:
D:\Java大失叔\workspace\BaseJava\bin
C:\Program Files\Java\jre1.8.0_261\lib
我們採用基目錄+包樹狀結構,就可以定位到某個類,例如:
D:\Java大失叔\workspace\BaseJava\bin\com\javadss\javase\ch04\PackageTest.class
C:\Program Files\Java\jre1.8.0_261\lib\java\lang\System.class
這裡的基目錄,就是類路徑,英文叫classpath。類路徑就是java編譯器或JVM用來定位類的基目錄,類路徑可以有多個,是一組路徑的集合。無論是編譯還是運行,都需要設置類路徑,類路徑的形式和作業系統相關。
在Windows環境下,採用分號(;)分隔,如果路徑中含有空格,需要用引號(「」)括起來,形式如下:
D:\Java大失叔\workspace\BaseJava\bin; 「C:\Program Files\Java\jre1.8.0_261\lib」;
在Linux環境下,採用冒號(:)分隔,形式如下:
usr/local/bin:usr/dss/java/bin
4.6.2編譯
我們假設有3個類:A、B、C。main方法在C中,C中訪問了A和B,同時還訪問了java.lang.System類。它們的結構如下:
其中A和B是空類,C類的程式碼如下:
package com.javadss.javase.ch04.ccc; import com.javadss.javase.ch04.aaa.A; import com.javadss.javase.ch04.bbb.B; public class C { public static void main(String[] args) { A a = new A(); B b = new B(); System.out.println("classpath"); } }
現在我們用命令行來編譯A、B、C,還記得編譯命令嗎?編譯命令如下:
javac -d 編譯後class的路徑 源文件
則編譯命令如下:
javac -d D:\Java大失叔\workspace\BaseJava\bin D:\Java大失叔\workspace\BaseJava\src\com\javadss\javase\ch04\aaa\A.java
javac -d D:\Java大失叔\workspace\BaseJava\bin D:\Java大失叔\workspace\BaseJava\src\com\javadss\javase\ch04\bbb\B.java
javac -d D:\Java大失叔\workspace\BaseJava\bin D:\Java大失叔\workspace\BaseJava\src\com\javadss\javase\ch04\ccc\C.java
編譯A、B的時候沒有問題,但是編譯C的時候,遇到了問題,報錯:
這是因為C類中引用了A和B,但是編譯命令中沒有指定A和B的絕對路徑,因此會報錯「程式包不存在」、「找不到符號」這些錯誤。我們可以在命令行中增加-classpath或-cp選項,設置A和B的類路徑,設置後的命令如下:
javac -cp D:\Java大失叔\workspace\BaseJava\bin -d D:\Java大失叔\workspace\BaseJava\bin D:\Java大失叔\workspace\BaseJava\src\com\javadss\javase\ch04\ccc\C.java
再次執行,編譯成功。有的同學可能要問了,C中也引用了java.lang.System類,為什麼不用設置System類的類路徑呢?這是因為System屬於JDK的類庫,javac編譯時,會默認搜尋JDK的類路徑。
當我們的程式引用了很多類,這些類分散在不同的地方,就需要把所有的類路徑都寫到命令行中,比如類路徑為:
D:\Java大失叔\workspace\BaseJava\bin;.;「C:\Program Files\Java\jre1.8.0_261\lib」;
注意,中間有一個「.」,這個表示當前目錄。當我們這樣寫的時候會導致命令行非常長,我們可以用設置環境變數classpath的方式來減少命令行的長度,設置環境變數的具體形式和作業系統有關,Windows命令格式如下:
set classpath=類路徑集合
例如:
set classpath= D:\Java大失叔\workspace\BaseJava\bin; 「C:\Program Files\Java\jre1.8.0_261\lib」;
我們在命令行窗口中執行上述命令後,在窗口關閉之前,所有的編譯命令都不需要用-cp選項來設置類路徑了。網上有很多網文或教程中,都喜歡在系統環境變數中設置classpath,這是筆者不推薦的。推薦的幾種做法是
- 在命令行中用-classpath或-cp選項
- 在命令行中設置classpath環境變數
- 編寫shell腳本,將設置classpath環境變數和編譯命令一起寫入腳本
事實上,編譯器會按照下面方式搜尋類:
- 從JDK的類庫中搜尋
- 從當前目錄下搜尋
- 從classpath環境變數中搜尋
- 從classpath選項中搜尋
如果搜尋類的時候發現了一個以上的同一個類,就會產生編譯錯誤。
另外,編譯器還會做很多其他工作,例如編譯器在搜尋類的時候,還會查看源文件,如果發現被引用的類的源文件比類文件新,還會自動的重新編譯源文件。
4.6.3運行
用命令行運行程式和編譯類似,我們也需要用-classpath或-cp選項指定類路徑,常用的命令格式為:
java -classpath 類路徑 包含main方法的類的完整類名
我們來運行上面的例子C類,則命令行如下:
javac -cp D:\Java大失叔\workspace\BaseJava\bin com.javadss.javase.ch04.ccc.C
同樣,對於JDK的核心類庫,我們不需要顯示的加到類路徑中。當然,我們也可以用設置classpath環境變數的方法預先設置,然後執行運行命令的時候可以不用加上-classpath選項了。
這裡需要注意一點,對於編譯器來說,總是會搜尋當前目錄(換句話說,會默認把當前目錄加入到類路徑),但是虛擬機JVM僅僅在不設置classpath環境變數,也不加-classpath或-cp選項的時候,才會把當前目錄加入到類路徑中。