<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Java虛擬機器器設計團隊有意把類載入階段中的“通過一個類的全限定名來獲取描述該類的二進位制位元組流”這個動作放到Java虛擬機器器外部去實現,以便讓應用程式自己決定如何去獲取所需的類。實現這個動作的程式碼被稱為“類載入器”(ClassLoader)。
對於任意一個類,都必須由載入它的類載入器和這個類本身一起共同確立其在Java虛擬機器器中的唯一性,每一個類載入器,都擁有一個獨立的類名稱空間。這句話可以表達得更通俗一些:比較兩個類是否“相等”,只有在這兩個類是由同一個類載入器載入的前提下才有意義,否則,即使這兩個類來源於同一個Class檔案,被同一個Java虛擬機器器載入,只要載入它們的類載入器不同,那這兩個類就必定不相等。
名稱 | 載入的類 | 說明 |
---|---|---|
Bootstrap ClassLoader(啟動類載入器) | JAVA_HOME/jre/lib | 無法直接存取 |
Extension ClassLoader(拓展類載入器) | JAVA_HOME/jre/lib/ext | 上級為Bootstrap,顯示為null |
Application ClassLoader(應用程式類載入器) | classpath | 上級為Extension |
自定義類載入器 | 自定義 | 上級為Application |
可通過在控制檯輸入指令,使得類被啟動類加器載入,它是用C++寫的,看不到原始碼;其他類載入器是用Java寫的,說白了就是一些Java類,比如擴充套件類載入器、應用類載入器。
//查詢所有被啟動類載入器載入的類 URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs(); for (URL url : urls) { System.out.println(url); }
//查詢到的結果 file:/C:/Program%20Files/Java/jre1.8.0_131/lib/resources.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/rt.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/sunrsasign.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/jsse.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/jce.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/charsets.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/jfr.jar file:/C:/Program%20Files/Java/jre1.8.0_131/classes
由上可以看出啟動類載入的都是jre和jre/lib目錄下的核心庫,具體路徑要看你的jre安裝在哪裡。
如果classpath和JAVA_HOME/jre/lib/ext 下有同名類,載入時會使用拓展類載入器載入。當應用程式類載入器發現拓展類載入器已將該同名類載入過了,則不會再次載入
URL[] urls = ((URLClassLoader) ClassLoader.getSystemClassLoader().getParent()).getURLs(); for (URL url : urls) { System.out.println(url); }
file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/access-bridge-64.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/cldrdata.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/dnsns.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/dns_sd.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/jaccess.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/jfxrt.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/localedata.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/nashorn.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/sunec.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/sunjce_provider.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/sunmscapi.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/sunpkcs11.jar file:/C:/Program%20Files/Java/jre1.8.0_131/lib/ext/zipfs.jar
這些類庫具體是什麼不重要,只需要知道不同的類庫可能是被不同的類載入器載入的。
URL[] urls = ((URLClassLoader) ClassLoader.getSystemClassLoader()).getURLs(); for (URL url : urls) { System.out.println(url); }
file:/{專案工程目錄}/bin/
這是當前java工程的bin目錄,也就是我們自己的Java程式碼編譯成的class檔案所在。
雙親委派模式,呼叫類載入器ClassLoader 的 loadClass 方法時,查詢類的規則。
loadClass原始碼
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { synchronized (getClassLoadingLock(name)) { // 首先查詢該類是否已經被該類載入器載入過了 Class<?> c = findLoadedClass(name); //如果沒有被載入過 if (c == null) { long t0 = System.nanoTime(); try { //看是否被它的上級載入器載入過了 Extension的上級是Bootstarp,但它顯示為null if (parent != null) { c = parent.loadClass(name, false); } else { //看是否被啟動類載入器載入過 c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { // ClassNotFoundException thrown if class not found // from the non-null parent class loader //捕獲異常,但不做任何處理 } if (c == null) { //如果還是沒有找到,先讓拓展類載入器呼叫findClass方法去找到該類,如果還是沒找到,就丟擲異常 //然後讓應用類載入器去找classpath下找該類 long t1 = System.nanoTime(); c = findClass(name); // 記錄時間 sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1); sun.misc.PerfCounter.getFindClasses().increment(); } } if (resolve) { resolveClass(c); } return c; } }
有一個描述類載入器載入類過程的術語:雙親委派模型。然而這是一個很有誤導性的術語,它應該叫做單親委派模型(Parent-Delegation Model)。但是沒有辦法,大家都已經這樣叫了。所謂雙親委派,這個親就是指ClassLoader
裡的全域性變數parent
,也就是父載入器。
雙親委派的具體過程如下:
為什麼要雙親委派?
答:確保類的全域性唯一性。
如果你自己寫的一個類與核心類庫中的類重名,會發現這個類可以被正常編譯,但永遠無法被載入執行。因為你寫的這個類不會被應用類載入器載入,而是被委託到頂層,被啟動類載入器在核心類庫中找到了。如果沒有雙親委託機制來確保類的全域性唯一性,誰都可以編寫一個java.lang.Object類放在classpath下,那應用程式就亂套了。
從安全的角度講,通過雙親委託機制,Java虛擬機器器總是先從最可信的Java核心API查詢型別,可以防止不可信的類假扮被信任的類對系統造成危害。
如果我們自己去實現一個類載入器,基本上就是繼承ClassLoader之後重寫findClass方法,且在此方法的最後調包defineClass。
protected Class<?> findClass(final String name) throws ClassNotFoundException { // 1、安全檢查 // 2、根據絕對路徑把硬碟上class檔案讀入記憶體 byte[] raw = getBytes(name); // 3、將二進位制資料轉換成class物件 return defineClass(raw); }
本篇文章就到這裡了,希望能夠給你帶來幫助,也希望您能夠多多關注it145.com的更多內容!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45