日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java类加载器_类加载器ClassLoader

發(fā)布時間:2025/4/5 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java类加载器_类加载器ClassLoader 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

上篇文章說到,Class類可以通過一個類的全限定名去加載類,那么底層是如何去加載的呢?這就是我們今天要聊的類加載器ClassLoader,其可以通過一個類的全限定名來獲取描述此類的二進(jìn)制字節(jié)流,也即是將編譯過后的Class文件加載到內(nèi)存中。

需要注意的是,即使是同一個類,類加載器不一樣,就必定不相等。

例如自定義了一個類加載器跟JVM默認(rèn)加載器進(jìn)行比對

/** *自定義類加載器 */class MyClassLoader extends ClassLoader { //類加載需要用到包名 String packageName; public MyClassLoader(String packageName) throws ClassNotFoundException { this.packageName = packageName; } @Override public Class> findClass(String name) throws ClassNotFoundException { String filename = name + ".class"; name = packageName+"."+name.substring(name.lastIndexOf("/")+1); InputStream is = null; try { is = new FileInputStream(new File(filename)); } catch (FileNotFoundException e) { e.printStackTrace(); } if (is == null) { return super.findClass(name); } try { byte[] bytes = new byte[is.available()]; is.read(bytes); //根據(jù)class對應(yīng)的二進(jìn)制文件,調(diào)用defineClass return defineClass(name,bytes,0,bytes.length); } catch (IOException e) { e.printStackTrace(); return null; } }}//參數(shù)是包名,類加載需要用到包名 MyClassLoader myClassLoader = new MyClassLoader("com.liusy.lang");//參數(shù)是java文件編譯過后的全路徑Object obj = myClassLoader.loadClass("H:/Code/IDEACODE/java_source_code/out/production/java_source_code/com/liusy/lang/ClassSource");System.out.println(obj);System.out.println(obj instanceof ClassSource);

上述代碼執(zhí)行結(jié)果如下

Java的3種類加載器

1、Bootstrap ClassLoader,頂級加載器。

啟動類加載器,加載$JAVA_HOME$/jre/lib下的核心類庫,也是所有加載器的頂級父類,由c++所寫。也可以用JVM參數(shù)-Xbootclasspath指定其加載的目錄。

//查看其加載的jar包信息Launcher.getBootstrapClassPath().getURLs()

2、Extension ClassLoader,擴(kuò)展類加載器

負(fù)責(zé)加載$JAVA_HOME$/jre/lib/ext目錄中的jar文件,是Application ClassLoader的父類。

//查看其加載的jar包信息URL[] urLs = ((URLClassLoader) ClassLoader.getSystemClassLoader().getParent()).getURLs();

3、Application ClassLoader,應(yīng)用程序類加載器

系統(tǒng)默認(rèn)加載器,負(fù)責(zé)加載用戶類所在路徑的類信息。可以由ClassLoader.getSystemClassLoader()直接獲取。

下圖是獲取系統(tǒng)類加載器以及獲取其父類,可以看到,AppClassLoader的父類就是ExtClassLoader,而ExtClassLoader的父類是null,這是因為頂級加載器BootstrapClassLoader是用C++所寫,java無法獲取其信息。

JVM的雙親委派模型(保證父類加載器會先加載類)

工作流程:如果一個類加載器收到了類加載的請求,首先不會自己去嘗試加載此類,而是把請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求都會傳送到頂層的啟動類加載器中,只有當(dāng)父加載器反饋無法完成此類的加載請求時,子加載器才會嘗試自己去加載。

就是默認(rèn)加載器不會一開始就去加載,一直往上拋,拋到最頂層,如果到最頂層了,此時又不能加載類,就會往下拋,直到加載完為止。

具體如下圖

這個雙親委派特性體現(xiàn)在ClassLoader類的loadClass方法中

?//name:類的全限定名 //resolve:是否鏈接到指定的類 protected Class> loadClass(String name, boolean resolve)throws ClassNotFoundException{ synchronized (getClassLoadingLock(name)) { //查看是否已被加載,如果是,則直接返回 Class> c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { //parent是父加載器,也就是一直往上拋 if (parent != null) { c = parent.loadClass(name, false); } else { //沒有父加載器,直接找頂級加載器 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } if (c == null) { long t1 = System.nanoTime(); //父類加載器無法加載的時候 //用自定義加載器去加載 c = findClass(name); } } if (resolve) { //鏈接到指定的類 resolveClass(c); } return c; }}

上面的loadClass方法開頭有一個加鎖的代碼,加鎖的對象的getClassLoadingLock是這個方法返回的。

protected Object getClassLoadingLock(String className) { Object lock = this; //parallelLockMap是一個Map對象 //parallelLockMap為空,則直接返回當(dāng)前ClassLoader if (parallelLockMap != null) { Object newLock = new Object(); //className作為key,如果存在,則直接返回舊值,如果不存在, //則將newLock作為value存入,此時lock就是newLock lock = parallelLockMap.putIfAbsent(className, newLock); if (lock == null) { lock = newLock; } } return lock;}

而parallelLockMap 是什么東西呢?如下,是一個ConcurrentHashMap對象,文檔顯示是該類不為null的時候當(dāng)前加載器就具有并行的功能。

private?final?ConcurrentHashMap?parallelLockMap;private ClassLoader(Void unused, ClassLoader parent) { this.parent = parent; //ParallelLoaders是靜態(tài)內(nèi)部類 if (ParallelLoaders.isRegistered(this.getClass())) { parallelLockMap = new ConcurrentHashMap<>(); package2certs = new ConcurrentHashMap<>(); domains = Collections.synchronizedSet(new HashSet()); assertionLock = new Object(); } else { // no finer-grained lock; lock on the classloader instance parallelLockMap = null; package2certs = new Hashtable<>(); domains = new HashSet<>(); assertionLock = this; }}private static class ParallelLoaders { private ParallelLoaders() {} //擁有并行能力的set集合 private static final Set> loaderTypes = Collections.newSetFromMap( new WeakHashMap, Boolean>()); static { synchronized (loaderTypes) { loaderTypes.add(ClassLoader.class); } } //往set集合上添加擁有并行能力的ClassLoader static boolean register(Class extends ClassLoader> c) { synchronized (loaderTypes) { if (loaderTypes.contains(c.getSuperclass())) { loaderTypes.add(c); return true; } else { return false; } } } //判斷某個ClassLoader是否擁有并行能力 static boolean isRegistered(Class extends ClassLoader> c) { synchronized (loaderTypes) { return loaderTypes.contains(c); } } }

另外,自定義類加載器官方推薦是重寫findClass()方法,這樣可以確保是符合雙親委派模型的。

=======================================================

我是Liusy,一個喜歡健身的程序員。

歡迎關(guān)注微信公眾號【Liusy01】,一起交流Java技術(shù)及健身,獲取更多干貨。

總結(jié)

以上是生活随笔為你收集整理的java类加载器_类加载器ClassLoader的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。