核心工具類
public class ClassPathUtil {
/**
* 獲取類的 .class 文件所在路徑(目錄或 JAR 文件路徑)
*/
public static String getClassPath(Class> cls) throws IOException {
if (cls == null) throw new NullPointerException();
URL url = getClassLocationURL(cls);
if (url == null) return null;
String path = url.getPath();
if ("jar".equalsIgnoreCase(url.getProtocol())) {
try {
path = new URL(path).getPath(); // 去掉 jar: 前綴
} catch (MalformedURLException ignored) {}
int idx = path.indexOf("!/");
if (idx != -1) path = path.substring(0, idx);
}
File file = new File(path.replaceAll("%20", " "));
return file.getCanonicalPath();
}
private static URL getClassLocationURL(Class> cls) {
String resource = cls.getName().replace('.', '/') + ".class";
ProtectionDomain pd = cls.getProtectionDomain();
if (pd != null) {
CodeSource cs = pd.getCodeSource();
if (cs != null) {
URL loc = cs.getLocation();
if (loc != null) {
if ("file".equals(loc.getProtocol())) {
try {
if (loc.toExternalForm().endsWith(".jar") || loc.toExternalForm().endsWith(".zip")) {
return new URL("jar:" + loc.toExternalForm() + "!/" + resource);
} else if (new File(loc.getFile()).isDirectory()) {
return new URL(loc, resource);
}
} catch (MalformedURLException ignored) {}
}
}
}
}
ClassLoader cl = cls.getClassLoader();
return cl != null ? cl.getResource(resource) : ClassLoader.getSystemResource(resource);
}
}
使用示例
// 獲取當前類所在路徑
String path = ClassPathUtil.getClassPath(MyClass.class);
System.out.println(path);
// 輸出示例: /home/user/project/target/classes 或 /home/user/project/lib/mylib.jar
// 獲取 JDK 類路徑
System.out.println(ClassPathUtil.getClassPath(String.class));
// 輸出: /usr/lib/jvm/java-11-openjdk/lib/modules (JDK 9+ 模塊系統)
應用場景
- 讀取同目錄下的配置文件(
new File(path, "config.properties"))。
- 掃描包下所有類文件(配合
Files.walk 或 JarFile API)。
- 插件系統動態加載外部 JAR 並定位資源。
注意事項
- JDK 9+ 模塊系統下,
String.class 等核心類位於 jrt:/ 文件系統,getPath() 返回 /modules/java.base,實際無法直接作為文件訪問。
- URL 路徑含空格會被編碼為
%20,需解碼後構造 File。
- 多類加載器環境(OSGi, Spring Boot FatJar, Tomcat)下,
getClassLoader() 返回的加載器可能不同,優先使用 ProtectionDomain 獲取 CodeSource。