簡(jiǎn)介
來(lái)自JEP371
隱藏類(lèi)劝贸,其他類(lèi)的字節(jié)碼不能直接使用的類(lèi)映九。隱藏類(lèi)適用于在運(yùn)行時(shí)生成類(lèi)并通過(guò)反射間接使用它們件甥。隱藏類(lèi)可以定義為訪(fǎng)問(wèn)控制嵌套的成員哼拔,并且可以獨(dú)立于其他類(lèi)進(jìn)行卸載。
原因
近幾年譬正,產(chǎn)生很多基于jvm的動(dòng)態(tài)語(yǔ)言曾我,例如groovy健民,kotlin等秉犹,基本都是基于動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)動(dòng)態(tài)語(yǔ)言的功能的,而像lambda表達(dá)式型诚,也是在運(yùn)行過(guò)程中傳輸一個(gè)字節(jié)碼,而該字節(jié)碼可以動(dòng)態(tài)生成一個(gè)類(lèi)并且實(shí)例化幸逆。
這樣就會(huì)在程序執(zhí)行的過(guò)程中產(chǎn)生很多的類(lèi),二基于傳統(tǒng)關(guān)于定于標(biāo)準(zhǔn)java類(lèi)的api上看(ClassLoader::defineClass
和Lookup::defineClass
)這些動(dòng)態(tài)生成的類(lèi)根本無(wú)法被識(shí)別出來(lái)楚昭。這樣這些動(dòng)態(tài)類(lèi)型很容易被發(fā)現(xiàn),并且聲明周期會(huì)變得很長(zhǎng)塘幅。
如果可以從標(biāo)準(zhǔn)API去定義一個(gè)可以隱藏且生命周期有限的類(lèi)电媳,那么肯定能夠提高所有基于jvm的語(yǔ)言的實(shí)現(xiàn)效率庆亡,例如:
-
java.lang.reflect.Proxy
可以定義隱藏類(lèi)作為實(shí)現(xiàn)代理接口的代理類(lèi) -
java.lang.invoke.StringConcatFactory
可以生成隱藏類(lèi)來(lái)保存常量連接方法 -
java.lang.invoke.LambdaMetaFactory
可以生成隱藏的nestmate類(lèi),以保存訪(fǎng)問(wèn)封閉變量的lambda主體 -
JavaScript引擎
可以為從JavaScript程序轉(zhuǎn)換的字節(jié)碼生成隱藏類(lèi)拼缝,因?yàn)楫?dāng)引擎不再使用這些類(lèi)時(shí)咧七,這些類(lèi)將被卸載
創(chuàng)建一個(gè)隱藏類(lèi)
普通類(lèi)是通過(guò)調(diào)用創(chuàng)建的
ClassLoader::defineClass
隱藏類(lèi)是通過(guò)調(diào)用創(chuàng)建的
java.lang.invoke.MethodHandles.Lookup#defineHiddenClass
具體的用法可以看jdk15中的java.lang.invoke.InnerClassLambdaMetafactory#generateInnerClass
defineHiddenClass(byte[] bytes, boolean initialize, ClassOption... options)
有三個(gè)參數(shù)
- bytes 一個(gè)符合java虛擬機(jī)規(guī)范的字節(jié)碼
- initialize 如果為true任斋,那么這個(gè)類(lèi)會(huì)被初始化
- options java類(lèi)的類(lèi)型詳見(jiàn)
java.lang.invoke.MethodHandles.Lookup.ClassOption
隱藏類(lèi)的使用
Lookup::defineHiddenClass
會(huì)返回一個(gè)Lookup
對(duì)象,我們可以調(diào)用Lookup::lookupClass
獲取這個(gè)隱藏類(lèi)的類(lèi)型仁卷,隱藏類(lèi)和普通的類(lèi)一樣使用,但是會(huì)有以下四點(diǎn)注意的地方:
Class::getName 返回不是二進(jìn)制名稱(chēng)的字符串
Class::getCanonicalName
返回值是null芒帕,表示示隱藏的類(lèi)沒(méi)有全限定名背蟆。(注意,Java語(yǔ)言中的匿名類(lèi)對(duì)象該方法的返回值也是null带膀。)在隱藏類(lèi)中聲明的所有字段都是不可修改的垛叨,無(wú)論是使用
Field::set
還是其他修改字段的方法都會(huì)拋出IllegalAccessException
(包括反射設(shè)置accessible
為True
時(shí))隱藏類(lèi)對(duì)象不能被 instrumentation agents修改嗽元,也不能被
JVM TI agents
重新定義或轉(zhuǎn)換敛纲。
調(diào)試中跟蹤隱藏類(lèi)
添加啟動(dòng)參數(shù)
-XX:+UnlockDiagnosticVMOptions
-XX:+ShowHiddenFrames
有三個(gè)api可以獲取隱藏類(lèi)的堆棧信息
Throwable::getStackTrace
Thread::getStackTrace
StackWalkerAPI