關(guān)于Java中的klass和class
Java的klass和class
vm加載的字節(jié)碼,也就是.class文件,被加載到方法區(qū)里面,叫Kclass,是一個C++對象,含有類的信息、虛方法表等
下文中說的mirror是指,JVM在加載了字節(jié)碼后,在堆里創(chuàng)建的Class對象,這個對象和方法區(qū)的Kclass相互指向,也就是說我們可以通過Kclass找到這個對象
我們new 一個對象,對象頭里面會有一個指針,指向方法區(qū)的Kclass
new Object().getClass()流程, 對象頭里面的指針–>方法區(qū)kClass–>堆Class對象
反射也是拿到堆里的Class對象
所有我們比較兩個對象類型是否相等,實際上就是比較兩個Class對象是否一樣
本節(jié)課,我們深入地理解一下反射中使用的Class類,Method類,F(xiàn)ield類這三個類。
其中,重點中的重點是Class類和Class對象。這個概念太容易混淆。
我在寫這篇文章之前,先在網(wǎng)上搜了一下,發(fā)現(xiàn)沒有一篇文章是能講得很清楚的。
確實很少有文章能講明白
知乎上有很多大牛,關(guān)于Class對象也曾留下過只言片語,但又不夠系統(tǒng),因為對于這些進行JVM開發(fā)的牛人而言,Class對象是一個不屑于說的問題。但就是在這樣的,開發(fā)者有點糊涂,大牛覺得不重要的地方,才容易產(chǎn)生知識的死角。而且網(wǎng)上有很多錯誤的概念,以訛傳訛,更加容易讓新手們搞不清楚。
先給結(jié)論,每一個Java類都有一個伴生的Class對象。
詳細解釋一下,定義這樣一個類:
class Main { }
那么當這個類所在的文件被加載,更準確地說,這個類被ClassLoader加載到JVM中的時候,Hotspot虛擬機會為這個類在虛擬機內(nèi)部創(chuàng)建一個叫做Klass的數(shù)據(jù)結(jié)構(gòu):
class Klass : public Metadata { friend class VMStructs; protected: // note: put frequently-used fields together at start of klass structure // for better cache behavior (may not make much of a difference but sure won't hurt) enum { _primary_super_limit = 8 }; jint _layout_helper; juint _super_check_offset; Symbol* _name; Klass* _secondary_super_cache; // Array of all secondary supertypes Array<Klass*>* _secondary_supers; // Ordered list of all primary supertypes Klass* _primary_supers[_primary_super_limit]; // java/lang/Class instance mirroring this class oop _java_mirror; // Superclass Klass* _super; // First subclass (NULL if none); _subklass->next_sibling() is next one Klass* _subklass; // Sibling link (or NULL); links all subklasses of a klass Klass* _next_sibling; Klass* _next_link; // The VM's representation of the ClassLoader used to load this class. // Provide access the corresponding instance java.lang.ClassLoader. ClassLoaderData* _class_loader_data; jint _modifier_flags; // Processed access flags, for use by Class.getModifiers. AccessFlags _access_flags; // Access flags. The class/interface distinction is stored here. // Biased locking implementation and statistics // (the 64-bit chunk goes first, to avoid some fragmentation) jlong _last_biased_lock_bulk_revocation_time; markOop _prototype_header; // Used when biased locking is both enabled and disabled for this type jint _biased_lock_revocation_count; TRACE_DEFINE_KLASS_TRACE_ID; // Remembered sets support for the oops in the klasses. jbyte _modified_oops; // Card Table Equivalent (YC/CMS support) jbyte _accumulated_modified_oops; // Mod Union Equivalent (CMS support) .... }
這個類的完整定義,大家可以去看hotspot/src/share/vm/oops/klass.hpp, 我們這里就不再多列了。這些屬性已經(jīng)足夠我們講解的了。
如果Main class被加載,那么虛擬機內(nèi)部就會為它創(chuàng)建一個 Klass
,它的 _name
屬性就是字符串 “Main”。
_primary_supers
代表了這個類的父類。比如,我們看IOException, 是Exception的子類,而Exception又是Throwable的子類。
那么,如果你去看IOException的 _primary_supers 屬性就會發(fā)現(xiàn),它是這樣的:[Throwable, Exception, IOException],后面5位為空。
其他的屬性我們先不看,以后有時間會慢慢再來講。
今天重點說一下oop,這個我猜是ordinary object pointer的縮寫,到底是什么的縮寫,其實我也不確定。
但我能確定的是,這種類型代表是一個真正的Java對象。比如說:
Main m = new Main();
這行語句里創(chuàng)建的 m 在JVM中,就是一個oop,是一個普通的Java對象,而Main在JVM里則是一個Klass。
大家理清了這里面的關(guān)系了嗎?我建議沒看懂的,再多看一遍。一般地來說,我不是很鼓勵新手學習JVM源代碼。但是有一些核心概念,如果能加以掌握的話,還是有利于快速掌握概念的本質(zhì)的。
好了。說了這么多,才剛來到我們今天的主題: java_mirror
。不起眼的一行:
// java/lang/Class instance mirroring this class oop _java_mirror;
注釋說得很清楚了,這個屬性代表的就是本class的Class對象。舉例來說,如果JVM加載了Main這個類,那么除了為Main創(chuàng)建了一個名為"Main"的Klass,還默默地背后創(chuàng)建一個object,并且把這個object 掛到了 Klass 的 _java_mirror
屬性上了。
那我們通過Java代碼能不能訪問到這個背后的對象呢?你肯定已經(jīng)猜到了,當然能啊,這就是Main的class對象啊。我們上節(jié)課已經(jīng)有兩種寫法來訪問它了啊:
Class m = Main.class; Class m = Class.forName("Main");
這兩種方法都能訪問到Main的Class object,也就是 Klass
上那個不起眼的 _java_mirror
。那么這個_java_mirror上定義的 newInstance 方法,其實最終也是通過JVM中的方法來創(chuàng)建真正的對象:
JVM_ENTRY(jobject, JVM_NewInstanceFromConstructor(JNIEnv *env, jobject c, jobjectArray args0)) JVMWrapper("JVM_NewInstanceFromConstructor"); oop constructor_mirror = JNIHandles::resolve(c); objArrayHandle args(THREAD, objArrayOop(JNIHandles::resolve(args0))); oop result = Reflection::invoke_constructor(constructor_mirror, args, CHECK_NULL); jobject res = JNIHandles::make_local(env, result); if (JvmtiExport::should_post_vm_object_alloc()) { JvmtiExport::post_vm_object_alloc(JavaThread::current(), result); } return res; JVM_END
這個函數(shù)到這里我們就不再往下追了,只要知道JVM可以通過 java_mirror
找到真正的 Klass
,然后再用這個 Klass
創(chuàng)建一個真正的對象就可以了。
到此這篇關(guān)于關(guān)于Java中的klass和class的文章就介紹到這了,更多相關(guān)Java的klass和class內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis-Plus 分頁插件配置的兩種方式實現(xiàn)
本文主要介紹了MyBatis-Plus 分頁插件配置的兩種方式實現(xiàn),包括使用PaginationInterceptor和MybatisPlusInterceptor兩種方式,具有一定的參考價值,感興趣的可以了解一下2025-03-03java 中 request.getSession(true、false、null)的區(qū)別
這篇文章主要介紹了java 中 request.getSession(true/false/null)的區(qū)別的相關(guān)資料,需要的朋友可以參考下2017-02-02詳解Jenkins 實現(xiàn)Gitlab事件自動觸發(fā)Jenkins構(gòu)建及釘釘消息推送
這篇文章主要介紹了Jenkins 實現(xiàn)Gitlab事件自動觸發(fā)Jenkins構(gòu)建及釘釘消息推送,應該會對大家學習Jenkins有所啟發(fā)2021-04-04