在 Java 開發過程中,獲取類的加載路徑或項目根路徑是常見需求,例如讀取配置文件、加載資源文件等場景。然而,由於類加載器機制、運行環境(IDE、打包後的 JAR、Web 容器)差異,不同獲取方式的表現各不相同。本文將系統梳理 5 種主流獲取路徑的方法,並通過實戰代碼驗證其在不同場景下的行為差異,助你精準選型。
package my;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class MyUrlDemo {
public static void main(String[] args) {
MyUrlDemo muDemo = new MyUrlDemo();
try {
muDemo.showURL();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showURL() throws IOException {
// 方式一:獲取類加載的根路徑(ClassPath 根目錄)
// 輸出示例:D:\git\daotie\daotie\target\classes
File f = new File(this.getClass().getResource("/").getPath());
System.out.println("方式一 - ClassPath 根路徑: " + f);
// 方式一補充:獲取當前類所在包目錄
// 輸出示例:D:\git\daotie\daotie\target\classes\my
File f2 = new File(this.getClass().getResource("").getPath());
System.out.println("方式一補充 - 當前類包路徑: " + f2);
// 方式二:獲取項目根路徑(基於相對路徑)
// 輸出示例:D:\git\daotie\daotie
File directory = new File("");
String courseFile = directory.getCanonicalPath();
System.out.println("方式二 - 項目根路徑: " + courseFile);
// 方式三:通過 ClassLoader 獲取資源路徑
// 輸出示例:file:/D:/git/daotie/daotie/target/classes/
URL xmlpath = this.getClass().getClassLoader().getResource("");
System.out.println("方式三 - ClassLoader 資源路徑: " + xmlpath);
// 方式四:獲取系統屬性 user.dir(最常用的項目根路徑)
// 輸出示例:D:\git\daotie\daotie
System.out.println("方式四 - user.dir: " + System.getProperty("user.dir"));
// 方式五:獲取完整類路徑(包含所有依賴 JAR)
System.out.println("方式五 - java.class.path: " + System.getProperty("java.class.path"));
}
}
target/classes),不受調用類包結構影響。target/classes/my),隨包層級變化。application.properties)。file:/xxx.jar!/),需用 getResourceAsStream() 讀取流。pom.xml 所在目錄)。java -jar /path/app.jar),結果會偏移。URL 對象,攜帶協議頭(file:/)。URL 處理資源的場景。new File(System.getProperty("user.dir"), "config/app.yml")。-classpath 或 -cp 參數值,包含所有依賴 JAR 路徑。| 場景 | 推薦方式 | 關鍵代碼 |
|---|---|---|
| 讀取 ClassPath 內資源文件 | 方式一/三 | getClass().getResourceAsStream("/config.yml") |
| 構建項目絕對路徑(日誌、上傳目錄) | 方式四 | new File(System.getProperty("user.dir"), "logs") |
| 排查類加載/依賴衝突 | 方式五 | System.getProperty("java.class.path") |
| 兼容 JAR 包內讀取 | 方式一 + 流 | getClass().getResourceAsStream(...) |
getResourceAsStream() 獲取輸入流。ServletContext.getRealPath("/")。掌握這 5 種路徑獲取方式的本質差異,關鍵在於理解ClassLoader 機制、JVM 工作目錄、打包形態(目錄 vs JAR)三者的交互影響。日常開發中,「讀資源用 Class.getResourceAsStream,存文件用 user.dir」 是最高效、最穩健的組合策略。