classpath簡介
classpath是java程序時擁有的一個系統變量,這個變量可以通過如下方式獲取
System.out.println(System.getProperty("java.class.path"));
為什么classpath設置了就是找不到類
1.首先,classpath只和應用程序類加載器有關,如果發生了class not found exception,首先確認是否異常出自哪個類加載器,出自哪個類加載器說明jvm使用哪個類加載器嘗試加載的
java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
如以上異常棧說明異常出自應用程序類加載器
2.當確認來自應用程序類加載器,需要確認classpath中是否包含目標類。
關於classpath的說明可以參考官方文檔,https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html
我的經驗總結是:如果目標類文件在某個目錄中,classpath應該包含這個目錄,如果目標類在某個目錄的某個jar包中或是zip包中,比如c.jar存在my_jars目錄下,那么classpath應該包含my_jars/c.jar或是my_jars/*,如果僅含有my_jars,是不會從目錄下的jar包加載類的。
3.正確設置classpath的方式
1.目標類是存在.class文件中,將其所在目錄的添加到classpath,這里需要注意目錄和包名對應。
2.目標類是存在jar包文件中,將該jar包的文件名或是所在目錄+"/*"添加到classpath
3.目錄+"/ *"只對從jar/zip包中加載有效,如果要某個目錄下的.class文件中加載類,使用目錄+"/ *"的方式,加載器會拋class not found異常。
classpath與類加載器的關系
我們都知道classpath與類加載有關,這究竟體現在哪里呢?我們知道在java中類加載的工作是通過類加載器完成的,當jvm啟動后,除了自帶的內建類加載器外,還會創建一個擴展類加載器和應用程序類加載器,這個過程在sun.misc.Launcher源碼中有體現。當應用程序類加載器創建好后,會作為系統默認的類加載器,具體在 類加載器文中詳細說明。
這個類加載器會讀取這個系統變量,並將其作為查找路徑。
public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
final String var1 = System.getProperty("java.class.path");
final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
public Launcher.AppClassLoader run() {
URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
return new Launcher.AppClassLoader(var1x, var0);
}
});
}
如何設置classpath這個變量
- 執行java時指定 -cp參數
- 未指定-cp參數時,java會讀取環境變量,這個變量的設置方式和操作系統有關,在linux/unix環境下,通過export CLASSPATH="xxx"方式可以執行,如果操作系統中沒有配置這個環境變量,則默認為".",即當前目錄。
通過man java驗證