//ExtClassLoader類中獲取路徑的代碼 private static File[] getExtDirs() { //加載<JAVA_HOME>/lib/ext目錄中的類庫 String s = System.getProperty("java.ext.dirs"); File[] dirs; if (s != null) { StringTokenizer st = new StringTokenizer(s, File.pathSeparator); int count = st.countTokens(); dirs = new File[count]; for (int i = 0; i < count; i++) { dirs[i] = new File(st.nextToken()); } } else { dirs = new File[0]; } return dirs; }
系統(System)類加載器/應用程序類加載器
指 Sun公司實現的sun.misc.Launcher$AppClassLoader。它負責加載系統類路徑java -classpath或-D java.class.path 指定路徑下的類庫,也就是咱們常常用到的classpath路徑,開發者能夠直接使用系統類加載器,通常狀況下該類加載是程序中默認的類加載器,經過ClassLoader#getSystemClassLoader()方法能夠獲取到該類加載器。
自定義類加載器
java
//該加載器能夠加載與本身在同一路徑下的Class文件 public class MyClassLoader extends ClassLoader{ @Override public Class<?> loadClass(String name) throws ClassNotFoundException{ try { String fileName=name.substring(name.lastIndexOf(".")+1)+".class"; InputStream is=getClass().getResourceAsStream(fileName); if(is==null){ //不在當前路徑下的類,例如Object類(JavaBean的父類),採用委派模型加載 return super.loadClass(name); }else{ //在當前路徑下的類,例如JavaBean類,直接經過本身加載其Class文件 byte[] b=new byte[is.available()]; is.read(b); return defineClass(name,b,0,b.length); } } catch (IOException e) { throw new ClassNotFoundException(); } } }
對於任意一個類,都須要由加載它的類加載器和類的全限定名一同肯定其在Java虛擬機中的惟一性。
只有被同一個類加載器加載的類纔可能會想等。相同的字節碼被不一樣的類加載器加載的類不想等。
bootstrap
public class ClassLoaderTest { public static void main(String[] args) throws Exception{ ClassLoader myLoader=new MyClassLoader(); Object classLoaderTest=myLoader.loadClass("com.loader.ClassLoaderTest").newInstance(); System.out.println(classLoaderTest.getClass()); System.out.println(classLoaderTest instanceof ClassLoaderTest); } }
class com.loader.ClassLoaderTest false
類加載器之間的層次關係,稱爲類加載器的雙親委派模型。雙親委派模型要求除了頂層的啓動類加載器外,其他類加載器都應該有本身的父類加載器。注意,這裏類加載器之間的父子關係通常不會以繼承的關係實現,而是使用組合關係來複用父加載器的代碼。
安全
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) {//對加載類的過程進行同步 // 首先,檢查請求的類是否已經被加載過了 // First, check if the class has already been loaded Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { c = parent.loadClass(name, false);//委派請求給父加載器 } else { //父加載器爲null,說明this爲擴展類加載器的實例,父加載器爲啓動類加載器 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // 若是父加載器拋出ClassNotFoundException // 說明父加載器沒法完成加載請求 // ClassNotFoundException thrown if class not found // from the non-null parent class loader } if (c == null) { // 若是父加載器沒法加載 // 調用自己的findClass方法來進行類加載 // If still not found, then invoke findClass in order // to find the class. long t1 = System.nanoTime(); c = findClass(name); // this is the defining class loader; record the stats sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { .. if (parent != null) {//父加載器不爲null,即父加載器爲ClassLoader類型 c = parent.loadClass(name, false);//委派請求給父加載器 } else {//父加載器爲null,說明this爲擴展類加載器的實例 c = findBootstrapClassOrNull(name);//經過啓動類加載器加載類 } .. }
/**經過啓動類加載器加載類 * Returns a class loaded by the bootstrap class loader; * or return null if not found. */ private Class findBootstrapClassOrNull(String name) { if (!checkName(name)) return null; return findBootstrapClass(name); }
// return null if not found 啓動類加載器經過本地方法加載類 private native Class findBootstrapClass(String name);默認狀況下,應用程序中的類由 應用程序類加載器 ( AppClassLoader )加載。該加載器加載 系統類路徑 下的類,所以通常也稱爲 系統類加載器 。