當前位置:
首頁 > 知識 > Java 基礎中一些值得聊的話題 載入篇

Java 基礎中一些值得聊的話題 載入篇

在開始Java的類載入旅程之前,可以先參考這裡(http://blog.csdn.net/liweisnake/article/details/8470285)了解一些類載入器在Tomcat中的應用。

在最初執行java這個命令時,便會調用 ClassLoader 的 getSystemClassLoader 方法顯式或者隱式載入 main 方法所在的類及其所引用的類。getSystemClassLoader 會返回 AppClassLoader,後者是 URLClassLoader 的一個子類。

先有雞還是先有蛋?

所以,最初的一個問題是:先有雞還是先有蛋?因為 ClassLoader 的整套體系是打包在 jre/lib/rt.jar 中的。只有 rt.jar 先被載入進來,才能夠載入別的類;但是 rt.jar 又是被誰載入的呢?自然就是大名鼎鼎的 BootstrapClassLoader。它就是「雞」。所以嚴格來講,BootStrapClassLoader 並不是整個體系中的一部分(可以用 -Xbootclasspath 指定bootstrap 載入的位置)。

當 rt.jar 被載入進來後,ClassLoader 會調用 getSystemClassLoader,其中最重要的一步就是初始化 Launcher、ExtClassLoader 以及AppClassLoader,另外就是將 ContextClassLoader 設為 AppClassLoader。ExtClassLoader 與 AppClassLoader 都是 URLClassLoader 的子類,分別會載入 java.ext.dirs 和 java.class.path 路徑下的 jar資源,前者一般指向 jre/lib/ext 下的所有jar,後者就是我們經常念叨的classpath。區分這兩個 ClassLoader 的主要目的是,讓他們形成層級關係,ExtClassLoader 為 AppClassLoader 的父 ClassLoader,有了層級關係,便可隨意使用雙親委託模型了。

ClassLoader extcl;

try {

extcl = ExtClassLoader.getExtClassLoader();

} catch (IOException e) {

throw new InternalError(

"Could not create extension class loader");

}

// Now create the class loader to use to launch the application

try {

loader = AppClassLoader.getAppClassLoader(extcl);

} catch (IOException e) {

throw new InternalError(

"Could not create application class loader");

}

// Also set the context class loader for the primordial thread.

Thread.currentThread().setContextClassLoader(loader);

ClassLoader究竟幹了什麼?

接下來一個比較重要的問題是ClassLoader究竟幹了什麼?通常我們只知道它載入了一個類進了jvm,但是具體做了什麼呢?

Java設計者把classloader載入一個類的過程分為4步:

第一步,從某個地方得到我們想要的位元組碼二進位流;

第二步,讀入位元組碼流並轉化為Class;

第三步,鏈接;

第四步,初始化。

其中,第二步一般比較固定,因此ClassLoader提供了defineClass來完成這步;

protected final Class defineClass(String name, byte[] b, int off, int len,

ProtectionDomain protectionDomain)

throws ClassFormatError

{

protectionDomain = preDefineClass(name, protectionDomain);

Class c = null;

String source = defineClassSourceLocation(protectionDomain);

try {

c = defineClass1(name, b, off, len, protectionDomain, source);

} catch (ClassFormatError cfe) {

c = defineTransformedClass(name, b, off, len, protectionDomain, cfe,

source);

}

postDefineClass(c, protectionDomain);

return c;

}

而 ClassLoader 提供了另一個方法 findClass 來完成第一步及第二步,即從某個地方讀入類的二進位流,然後調用 defineClass 返回 Class

protected Class findClass(final String name)

throws ClassNotFoundException

ClassLoader提供了resolveClass方法完成第三步鏈接的工作。

protected final void resolveClass(Class c)

除非特殊需要,否則盡量重載 findClass 而不是 loadClass

loadClass 是 Java 1.0 就存在的類,為了增強可擴展性,將findClass和resolveClass封裝到了loadClass中,一般我們只需要定義類的載入路徑,因此僅需覆蓋findClass。

通常我們顯示載入類一般會用到ClassLoader.loadClass、Class.forName,他們的區別見這裡(http://blog.csdn.net/liweisnake/article/details/8857744)。

resolveClass做了什麼?

resolveClass最終調用了一個本地方法做link,這裡的link主要做了這麼幾步事情:

驗證Class以確保類裝載器格式和行為正確;

準備後續步驟所需的數據結構;

解析所引用的其他類。

ClassNotFoundException、NoClassDefFoundError、ClassCastException常見問題

ClassNotFoundException一般發生在顯式類載入;NoClassDefFoundError一般發生在隱式載入;ClassCastException一般發生在jar包衝突,比如某個jar包已經被更上層的載入器載入了,但你卻要求他強制轉為下層載入器載入的同名類;

鏈接的相關知識

接下來講講鏈接的相關知識。

為什麼會發明鏈接器?

最初程序員寫程序都在一個文件里,隨著程序規模的增加,逐漸發現越來越難以維護,擴展。於是,分多個文件和模塊就成為必然。

但是文件間必然相互調用,這就帶來了另一個問題:文件A引用了B的某個變數或方法,但是運行時A並不知道他們在內存中的位置。於是人們發明了鏈接,這種方式會在編譯階段將需要引用的變數或者方法作個記號,這時形成A.o和B.o兩個目標文件;通過ld鏈接器的鏈接,會將B中變數或方法的地址重新修改A的記號最終形成一個可執行文件,實際上就是把A和B合在一起工作了。

這種方式就是靜態鏈接

但是靜態鏈接有個問題,比如A需要B模塊的方法,C需要B模塊的變數,D需要B模塊的方法……如此一來,當我們編譯為A, C, D幾個可執行文件時,他們都會在內存中引用B,即B在內存中有多份拷貝。這帶來很多問題:首先浪費了內存;其次修改了B模塊需要重新修改並發布A, C, D幾個可執行文件,這是非常不方便的;於是動態鏈接的一個思想是在A, C, D調用時再確定記號的地址,而B則通過延遲載入的方式按需載入到內存(如果已經載入則不再重複)。這樣一來,內存中總是只有一份B的拷貝,解決了上面的問題。Java的類載入機制即是這種靈活的方式。

想要系統學習Java知識 加入學習群一四四九零一零七六 可以免費學習java還有大量學習乾貨哦

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 IT技術java交流 的精彩文章:

當你寫Java HelloWorld時候,背後到底發生什麼?
解析JavaScript函數的多種寫法
C語言 代碼之坦克大戰

TAG:IT技術java交流 |

您可能感興趣

不覺得 Sense 8 中映射的社會話題更值得一聊嗎
他都不會老啊!金在中 Rising Sun 時期舊圖成為話題
Red Velvet Wendy金髮造型在北邊成話題!本來的發色不是很好嗎?
讓人大打出手的AJ又回來了!今年更多的話題或許還需要Virgil Abloh的支持?
當楊天寶佔領話題榜的時候,別忘了還有另一個Angela
再次因「美貌」而登上了熱搜!RedVelvet 成員 Irene 機場照成為話題
YG背鍋?BlackPink Lisa 入鏡引擁堵成為話題
Kylie Jenner首次談到整容話題!「我真的沒動過刀」!
話題|你老買converse和vans大概是因為……
Redvelvet 艾琳 「不經意間的皺眉」成為話題
小圈子話題—Instagram 推出個性化 Stories 分享功能
Air Jordan 3 Tinker只是開胃,聊天記錄曝光一大波話題Air Jordan正在靠近!
話題丨Yeezy挑戰iPhone銷量!不限量真的好嗎?
美容話題 | Peter Philips 顏色是情感的化身
熱議話題!反鉤 TS x Air Jordan 1 市場行情如何了?
比冠軍套裝話題度還高!倫納德能否成為New Balance的「下一個庫里」呢?
「四胞胎」的顏值巔峰?RedVelvet 出道曲舊照成為話題
老外最想聊的話題之Healthy Eating&Tea TalK
Redvelvet 成員 Wendy「清爽」機場照成為話題
Angelababy又一部現代劇?女性話題題材?配角陣容強大