先有Class還是先有Object?
點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)
所有的類都是Class類的實(shí)例,Object是類,那么Object也是Class類的一個(gè)實(shí)例。 所有的類都最終繼承自O(shè)bject類,Class是類,那么Class也繼承自O(shè)bject。
那到底是先有Class還是先有Object?JVM 是怎么處理這個(gè)“雞·蛋”問(wèn)題呢?
針對(duì)這個(gè)問(wèn)題,我在知乎上看到了 R 大的一個(gè)回答,正好解答了我心中的疑惑,就分享出來(lái)給各位小伙伴一個(gè)參考和啟發(fā)~
每次看 R 大的內(nèi)容,總是感覺(jué)膝蓋忍不住要跪一下,只能說(shuō)寫(xiě)過(guò) JVM 的男人就是不一樣。喜歡研究 CPP 源碼的話小伙伴可以再深入學(xué)習(xí)下,一定會(huì)有所收獲。
作者:RednaxelaFX,整理:沉默王二,參考鏈接:https://www.zhihu.com/question/30301819/answer/47539163
“雞?蛋”問(wèn)題通常都是通過(guò)一種叫“自舉”(bootstrap)的過(guò)程來(lái)解決的。
“雞蛋問(wèn)題”的根本矛盾就在于假定了“雞”或“蛋”的其中一個(gè)要先進(jìn)入“完全可用”的狀態(tài)。而許多現(xiàn)實(shí)中被簡(jiǎn)化為“雞蛋問(wèn)題”的情況實(shí)際可以在“混沌”中把“雞”和“蛋”都初始化好,而不存在先后問(wèn)題;在它們初始化的過(guò)程中,兩者都不處于“完全可用”狀態(tài),而完成初始化后它們就同時(shí)都進(jìn)入了可用狀態(tài)。
打個(gè)比方,番茄炒蛋。并不是要先把番茄完全炒好,然后把雞蛋完全炒好,然后把它們混起來(lái);而是先炒番茄炒到半熟,再炒雞蛋炒到半熟,然后把兩個(gè)半熟的部分混在一起同時(shí)炒熟。
對(duì)于先有Class還是先有Object這個(gè)問(wèn)題來(lái)說(shuō),題主假設(shè)所有的類都是Class類的實(shí)例,Object是類,那么Object也是Class類的一個(gè)實(shí)例,這個(gè)假設(shè)就是錯(cuò)的。
java.lang.Object是一個(gè)Java類,但并不是java.lang.Class的一個(gè)實(shí)例。后者只是一個(gè)用于描述Java類與接口的、用于支持反射操作的類型。這點(diǎn)上Java跟其它一些更純粹的面向?qū)ο笳Z(yǔ)言(例如Python和Ruby)不同。
第二個(gè)假設(shè)“所有的類都最終繼承自O(shè)bject類,Class是類,那么Class也繼承自O(shè)bject”是對(duì)的,java.lang.Class是java.lang.Object的派生類,前者繼承自后者。
雖然第1個(gè)假設(shè)不對(duì),但“雞蛋問(wèn)題”仍然存在:在一個(gè)已經(jīng)啟動(dòng)完畢、可以使用的Java對(duì)象系統(tǒng)里,必須要有一個(gè)java.lang.Class實(shí)例對(duì)應(yīng)java.lang.Object這個(gè)類;而java.lang.Class是java.lang.Object的派生類,按“一般思維”,前者應(yīng)該要在后者完成初始化之后才可以初始化…
事實(shí)是:這些相互依賴的核心類型完全可以在“混沌”中一口氣都初始化好,然后對(duì)象系統(tǒng)的狀態(tài)才叫做完成了“bootstrap”,后面就可以按照J(rèn)ava對(duì)象系統(tǒng)的一般規(guī)則去運(yùn)行。JVM、JavaScript、Python、Ruby等的運(yùn)行時(shí)都有這樣的bootstrap過(guò)程。
在“混沌”(boostrap過(guò)程)里,JVM可以為對(duì)象系統(tǒng)中最重要的一些核心類型先分配好內(nèi)存空間,讓它們進(jìn)入[已分配空間]但[尚未完全初始化]狀態(tài)。
此時(shí)這些對(duì)象雖然已經(jīng)分配了空間,但因?yàn)闋顟B(tài)還不完整所以尚不可使用。然后,通過(guò)這些分配好的空間把這些核心類型之間的引用關(guān)系串好。
到此為止所有動(dòng)作都由JVM完成,尚未執(zhí)行任何Java字節(jié)碼。然后這些核心類型就進(jìn)入了[完全初始化]狀態(tài),對(duì)象系統(tǒng)就可以開(kāi)始自我運(yùn)行下去,也就是可以開(kāi)始執(zhí)行Java字節(jié)碼來(lái)進(jìn)一步完成Java系統(tǒng)的初始化了。
在HotSpot VM里,有一個(gè)叫做“Universe”的C++類用于記錄對(duì)象系統(tǒng)的總體狀態(tài)。它有這么兩個(gè)有趣的字段記錄當(dāng)前是處于bootstrapping階段還是已經(jīng)完全初始化好:
static bool is_bootstrapping() { return _bootstrapping; }
static bool is_fully_initialized() { return _fully_initialized; }
然后Universe::genesis()函數(shù)會(huì)在bootstrap階段中創(chuàng)建核心類型的對(duì)象模型,其中會(huì)調(diào)用SystemDictionary::initialize()來(lái)初始化對(duì)象系統(tǒng)的核心類型,其中會(huì)進(jìn)一步跑到SystemDictionary::initialize_preloaded_classes()來(lái)創(chuàng)建java.lang.Object、java.lang.Class等核心類型。
這個(gè)函數(shù)在加載了java.lang.Object、java.lang.Class等核心類型后會(huì)調(diào)用Universe::fixup_mirrors()來(lái)完成前面說(shuō)的“把引用關(guān)系串起來(lái)”的動(dòng)作:
// Fixup mirrors for classes loaded before java.lang.Class.
// These calls iterate over the objects currently in the perm gen
// so calling them at this point is matters (not before when there
// are fewer objects and not later after there are more objects
// in the perm gen.
Universe::initialize_basic_type_mirrors(CHECK);
Universe::fixup_mirrors(CHECK);
void Universe::fixup_mirrors(TRAPS) {
// Bootstrap problem: all classes gets a mirror (java.lang.Class instance) assigned eagerly,
// but we cannot do that for classes created before java.lang.Class is loaded. Here we simply
// walk over permanent objects created so far (mostly classes) and fixup their mirrors. Note
// that the number of objects allocated at this point is very small.
// ...
}
就是這樣:“Object里有一個(gè)成員變量指向Class類實(shí)例c,c保存這個(gè)Object成員、方法的名字和地址的Map映射用作反射?!鄙婕暗街黝愑羞@么幾個(gè):
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.hpp#l399
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/memory/universe.cpp#l259
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/ade5be2b1758/src/share/vm/classfile/systemDictionary.cpp#l1814
往 期 推 薦
1、拖動(dòng)文件就能觸發(fā)7-Zip安全漏洞,波及所有版本
3、一次 SQL 查詢優(yōu)化原理分析:900W+ 數(shù)據(jù),從 17s 到 300ms
4、Redis數(shù)據(jù)結(jié)構(gòu)為什么既省內(nèi)存又高效?
點(diǎn)分享
點(diǎn)收藏
點(diǎn)點(diǎn)贊
點(diǎn)在看





