先來一張java中JVM內(nèi)的類加載器的層次體系結(jié)構(gòu),總整體上觀看JVM中所包含的classLoader有哪些,以及它們之間的關(guān)系:
說到
classLoader
嬉橙,從名字也可以知道它的作用亚脆。不就是加載類(class)的么,那么如何加載嘹裂?何時(shí)加載妄壶?誰來加載呢等等問題,下面我就要來說說寄狼,實(shí)踐實(shí)踐丁寄。當(dāng)然了,我還是先從class
這個(gè)在OOP中屬于基石核心的概念來說說泊愧,并看看它是在java平臺(tái)是如何來的伊磺,具體長什么樣哈?
Class文件結(jié)構(gòu)?
java平臺(tái)的強(qiáng)大跨平臺(tái)特性就是靠著這個(gè)東東啊删咱。只要在java虛擬機(jī)上運(yùn)行開發(fā)的語言屑埋,像java,jruby,groovy等語言痰滋,都是運(yùn)行在JVM基礎(chǔ)之上的摘能。那么在源代碼形式下续崖,通過各自語言的編譯器,按照java虛擬機(jī)規(guī)范(JVM要求在class文件中使用許多強(qiáng)制性的語法和結(jié)構(gòu)化約束)處理团搞,就能得到一個(gè)通用的袜刷,機(jī)器無關(guān)的執(zhí)行平臺(tái)的字節(jié)碼文件(*.class)。就如下圖所示:
那么莺丑,這個(gè)萬能的class結(jié)構(gòu)是什么樣的呢著蟹?在java語言的jdk中是如何表示的?
由于JVM底層是c語言支持的梢莽,class文件當(dāng)然要通過符合C語言的數(shù)據(jù)結(jié)構(gòu)來構(gòu)造了萧豆。class的數(shù)據(jù)結(jié)構(gòu)如下:
無符號(hào)數(shù)數(shù)據(jù)基本數(shù)據(jù)類型,以
u1,u2,u4,u8
來分別代表一個(gè)字節(jié)(八位bit昏名,也就是八個(gè)坑涮雷,每個(gè)坑只能放0和1),2個(gè)字節(jié)轻局,4個(gè)字節(jié)和8個(gè)字節(jié)的無符號(hào)數(shù)洪鸭。其中還包含表的概念,表是由多個(gè)無符號(hào)數(shù)或者其他表作為數(shù)據(jù)項(xiàng)構(gòu)成的符合數(shù)據(jù)類型,所有的表習(xí)慣性的以”_info”結(jié)尾。整個(gè)class文件本質(zhì)上就是一張表嚷量。
Class {
u4 magic; // 1 個(gè) 魔數(shù)
u2 minor_version; // 1 副版本號(hào)
u2 major_version; // 1 主版本號(hào)
u2 constant_pool_count; // 1 常量池計(jì)數(shù)器
cp_info constant_pool; // constant_pool_count - 1 常量池?cái)?shù)據(jù)區(qū)
u2 access_flags; // 1 訪問標(biāo)識(shí)
u2 this_class; // 1 類索引
u2 super_class; // 1 父類索引
u2 interfaces_count; // 1 接口計(jì)數(shù)器
u2 interfaces; // interfaces_count 接口信息數(shù)據(jù)區(qū)
u2 fields_count; // 1 字段計(jì)數(shù)器
field_info fields; //fields_count 字段信息數(shù)據(jù)區(qū)
u2 methods_count; // 1 方法計(jì)數(shù)器
method_info methods; // methods_count 方法信息數(shù)據(jù)區(qū)
u2 attributes_count; // 1 屬性計(jì)數(shù)器
attribute_info attributes; // attributes_count 屬性信息數(shù)據(jù)區(qū)
}
可以看到,在OOP中class對(duì)象所涉及到的屬性蜓竹,方法都有自己對(duì)應(yīng)的表(field_info,method_info),其他的一些是其他信息的記錄储藐。
class文件是一組以8位字節(jié)為基礎(chǔ)單位的二進(jìn)制流俱济,各個(gè)數(shù)據(jù)項(xiàng)嚴(yán)格按照順序緊湊的排列在Class文件中,中間沒有任何的分隔符钙勃。
這使得整個(gè)Class文件中存儲(chǔ)的內(nèi)容集合全部都是程序運(yùn)行的必要數(shù)據(jù)蛛碌,沒有空隙存在。
那當(dāng)java文件經(jīng)過編譯得到的class的文件是什么樣的辖源?
我們?nèi)羰窍胍炊甤lass文件中常量池
內(nèi)容蔚携,首先需要先知道常量池中14種常量池的結(jié)構(gòu),如下圖:
理論上知道了class內(nèi)部結(jié)構(gòu)同木,那么就可以自己編寫一個(gè)簡單java程序浮梢,并用javac命令將該java源代碼文件編譯成字節(jié)碼跛十,在用編輯器打開該字節(jié)碼16進(jìn)制可以看到:
(現(xiàn)在我們看看class的二進(jìn)制文件:(用了簡陋畫圖工具制作的彤路,我使用JDK1.8來操作〗嬗常看懂就就行(▔^▔)/ ))
臥槽洲尊,畫個(gè)圖远豺,洪荒之力都出來了。好累….好了坞嘀,關(guān)于java中class文件內(nèi)容就說到這躯护。class文件中內(nèi)容包含挺多數(shù)據(jù)的,這些數(shù)據(jù)就決定了當(dāng)類加載器加載該類丽涩,形成實(shí)例對(duì)象后具備那些功能啦棺滞。那么反編譯工具如何得到j(luò)ava源文件內(nèi)容的問題也就明白了,還有其他像一些動(dòng)態(tài)加載和代理增強(qiáng)功能實(shí)現(xiàn)矢渊,都是可以直接通過字節(jié)碼進(jìn)行操作實(shí)現(xiàn)的继准。
想看更詳細(xì)內(nèi)容可以看這篇:JVM詳解博客
class文件如何被加載到JVM?
在class文件通過源代碼編譯生成后矮男,我們也知道class文件內(nèi)具體的二進(jìn)制數(shù)據(jù)內(nèi)容代表什么了移必,下面應(yīng)該了解了解class文件是如何被加載到JVM虛擬機(jī)中的。類的加載當(dāng)然與classLoader密不可分了毡鉴。在java虛擬機(jī)中崔泵,類加載全過程包括:加載,驗(yàn)證猪瞬,準(zhǔn)備憎瘸,解析和初始化
五個(gè)階段。在加載階段陈瘦,虛擬機(jī)需要完成以下3件事情:
1. 通過一個(gè)類的全限定名來獲取定義此類的二進(jìn)制字節(jié)流含思。(可以從本地文件,網(wǎng)絡(luò)中甘晤,運(yùn)行時(shí)動(dòng)態(tài)生成含潘,數(shù)據(jù)庫文件等等地方獲取類字節(jié)流)
2. 將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)。
3. 在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象线婚,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)訪問入口遏弱。
我在此說的就是這個(gè)加載
階段過程。
JVM類加載器種類:
Bootstrap classLoader(引導(dǎo)類加載器):
該類負(fù)責(zé)將存在\lib目錄中的塞弊,或者被-Xbootclasspath參數(shù)所指定的路徑中的漱逸,并且是虛擬機(jī)識(shí)別的(eg: rt.jar,名字不符合規(guī)范的即使放在lib中也不會(huì)被加載)類庫加載到虛擬機(jī)內(nèi)存中。啟動(dòng)類加載器無法被java程序直接引用游沿。負(fù)責(zé)加載JDK中的核心類庫饰抒,如:rt.jar、resources.jar诀黍、charsets.jar等袋坑。Extension ClassLoader(拓展類加載器):
這個(gè)加載器由sun.misc.Launcher$ExtClassLoader實(shí)現(xiàn),負(fù)責(zé)加載\lib\ext目錄中眯勾,或者被java.ext.dirs系統(tǒng)環(huán)境變量指定路徑中的所有類庫枣宫,開發(fā)者可以直接使用擴(kuò)展類加載器婆誓。.Application ClassLoader(應(yīng)用系統(tǒng)程序類加載器):
這個(gè)類加載器由sun.misc.Launcher$AppClassLoader實(shí)現(xiàn),由于這個(gè)類加載器是ClassLoader中的getSystemClassLoader方法的返回值也颤,所以一般稱為系統(tǒng)類加載器洋幻。它負(fù)責(zé)加載用戶類路徑(CLASSPATH)上所指定的類庫,開發(fā)者可以直接使用這個(gè)類加載器翅娶。通常我們自己寫的java類不就是通過該加載器獲取*.class中內(nèi)容文留,并加載對(duì)應(yīng)的Class對(duì)象的么
。Custom ClassLoader(自定義類加載器):
想要自己實(shí)現(xiàn)一個(gè)類加載器竭沫,只需要繼承ClassLoader類即可厂庇。關(guān)于自定義類加載器有什么作用,如何具體的實(shí)現(xiàn)自定義類加載器输吏,需要在另外的文章中說了权旷。
在這個(gè)加載階段,對(duì)于一個(gè)非數(shù)組類
加載階段(或者說加載階段中獲取二進(jìn)制字節(jié)流動(dòng)作)是我們開發(fā)人員可控性最強(qiáng)的贯溅,因?yàn)樵撾A段既可以使用系統(tǒng)提供的引導(dǎo)類加載器完成拄氯,也可以有我們開發(fā)人員自定義的類加載器去完成,也就是說開發(fā)人員可以自定義類加載去控制字節(jié)流的獲取方式它浅。
對(duì)于數(shù)組類
而言译柏,情況有所不同,數(shù)組類本身不通過類加載創(chuàng)建姐霍,它是由Java虛擬機(jī)直接創(chuàng)建的鄙麦。但是數(shù)組類里面的數(shù)據(jù)類型的加載就與類加載器有關(guān)了:
- 若是數(shù)組的組件類型(ComponentType)是引用類型,那么就采用常規(guī)類加載器加載這個(gè)類镊折,該數(shù)組將在該組件類型的類加載器的類名稱空間上被標(biāo)識(shí)胯府。
- 若是組件類型不是引用類型(eg: int[]),java虛擬機(jī)將會(huì)把該數(shù)組標(biāo)記為與引導(dǎo)類加載器關(guān)聯(lián)(Bootstarp classLoader)用來確定一個(gè)類的唯一性恨胚。
ClassLoader加載class過程
類加載器層次關(guān)系是雙親委派模型
骂因,該模型要求除了頂層的類加載器外,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器赃泡。這里的類加載器之間的父子關(guān)系一般不會(huì)以繼承關(guān)系來實(shí)現(xiàn)寒波,而都是使用組合關(guān)系來復(fù)用父加載器的代碼。本來想寫寫雙親委派的具體好處升熊,和劣勢(shì)的俄烁,因?yàn)槠螅土砥鹞恼聛碚f到說到级野。
Bootstrap classLoader
/\
/||\
Extenssion ClassLoader
/\
/||\
Application ClassLoader
/| |\
User ClassLoader User ClassLoader(自定義類加載器)
看看JDK中關(guān)于系統(tǒng)類加載器代碼:java.lang.ClassLoader.java
:
public static ClassLoader getSystemClassLoader() {
initSystemClassLoader(); //初始化獲取sun.misc.Launcher中的AppClassLoader類加載器
if (scl == null) {
return null;
}
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkClassLoaderPermission(scl, Reflection.getCallerClass());
}
return scl;
}
// The class loader for the system
// @GuardedBy("ClassLoader.class")
private static ClassLoader scl;
// Set to true once the system class loader has been set
// @GuardedBy("ClassLoader.class")
private static boolean sclSet;
private static synchronized void initSystemClassLoader() {
if (!sclSet) {
if (scl != null)
throw new IllegalStateException("recursive invocation");
sun.misc.Launcher l = sun.misc.Launcher.getLauncher(); //加載sun.misc,Launcher類
if (l != null) {
Throwable oops = null;
scl = l.getClassLoader(); //加載sun.misc,Launcher類中AppClassLoader
try {
scl = AccessController.doPrivileged(
new SystemClassLoaderAction(scl));
} catch (PrivilegedActionException pae) {
oops = pae.getCause();
if (oops instanceof InvocationTargetException) {
oops = oops.getCause();
}
}
if (oops != null) {
if (oops instanceof Error) {
throw (Error) oops;
} else {
// wrap the exception
throw new Error(oops);
}
}
}
sclSet = true; //若為真页屠,表示系統(tǒng)類加載器加載成功完成
}
}
上面可以看到,在ClassLoader類中,initSystemClassLoader
方法會(huì)加載sun.misc.Launcher中的AppClassLoader屬性值卷中,
就是獲取應(yīng)用類加載器矛双。
那么該類的作用就是將CLASSPATH中java庫所有二進(jìn)制類字節(jié)流加載到方法區(qū)(運(yùn)行常量池渊抽,類型信息蟆豫,字段信息,方法信息懒闷,類加載器引用等)中十减。
而引導(dǎo)類加載器Bootstrap ClassLoader是JVM啟動(dòng)的時(shí)候,就會(huì)自動(dòng)創(chuàng)建該實(shí)例愤估。
那看看sun.misc.Launcher源碼帮辟,就可以知道拓展類加載器和應(yīng)用類加載器的具體加載過程:(該Launcher類在rt.jar包中,該包放置所有J2SE的必要類)
當(dāng)JVM啟動(dòng)創(chuàng)建Bootstrap ClassLoader時(shí)候玩焰,就會(huì)加載rt.jar包中所有二進(jìn)制字節(jié)流類信息由驹,到JVM中的方法區(qū)中。
然后昔园,通過這些全限定的類字節(jié)文件蔓榄,就可以創(chuàng)建對(duì)應(yīng)的類對(duì)象實(shí)例,并將實(shí)例保存到Heap
中默刚。
public class Launcher {
private static URLStreamHandlerFactory factory = new Factory();
private static Launcher launcher = new Launcher();
public static Launcher getLauncher() {
return launcher;
}
private ClassLoader loader;
//ClassLoader.getSystemClassLoader會(huì)調(diào)用此方法
public ClassLoader getClassLoader() {
return loader;
}
public Launcher() {
// 1. 創(chuàng)建ExtClassLoader
ClassLoader extcl;
try {
extcl = ExtClassLoader.getExtClassLoader();
} catch (IOException e) {
throw new InternalError(
"Could not create extension class loader");
}
// 2. 用ExtClassLoader作為parent去創(chuàng)建AppClassLoader
try {
loader = AppClassLoader.getAppClassLoader(extcl);
} catch (IOException e) {
throw new InternalError(
"Could not create application class loader");
}
// 3. 設(shè)置AppClassLoader為ContextClassLoader
Thread.currentThread().setContextClassLoader(loader);
//...
}
static class ExtClassLoader extends URLClassLoader {
private File[] dirs;
public static ExtClassLoader getExtClassLoader() throws IOException
{
final File[] dirs = getExtDirs();
return new ExtClassLoader(dirs);
}
public ExtClassLoader(File[] dirs) throws IOException {
super(getExtURLs(dirs), null, factory);
this.dirs = dirs;
}
private static File[] getExtDirs() {
String s = System.getProperty("java.ext.dirs");
File[] dirs;
//...
return dirs;
}
}
/**
* The class loader used for loading from java.class.path.
* runs in a restricted security context.
*/
static class AppClassLoader extends URLClassLoader {
public static ClassLoader getAppClassLoader(final ClassLoader extcl)
throws IOException
{
final String s = System.getProperty("java.class.path");
final File[] path = (s == null) ? new File[0] : getClassPath(s);
URL[] urls = (s == null) ? new URL[0] : pathToURLs(path);
return new AppClassLoader(urls, extcl);
}
AppClassLoader(URL[] urls, ClassLoader parent) {
super(urls, parent, factory);
}
/**
* Override loadClass so we can checkPackageAccess.
*/
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
int i = name.lastIndexOf('.');
if (i != -1) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
//
sm.checkPackageAccess(name.substring(0, i));
}
}
return (super.loadClass(name, resolve));
}
}
}
可以看到甥郑,當(dāng)獲取AppClassLoader的時(shí)候,就loader字段賦值時(shí)候荤西,是通過傳遞extcl
變量澜搅,通過父類加載器去完成的。
引導(dǎo)類是加載java運(yùn)行是必要的類庫文件邪锌。
系統(tǒng)類加載器則是我們開發(fā)中經(jīng)常寫的源代碼編譯成字節(jié)碼勉躺,加載字節(jié)碼類信息到JVM方法區(qū)域中的工具。
因?yàn)椴煌募虞d器的命名空間會(huì)對(duì)相互加載的類的訪問性觅丰,可見性等都會(huì)有影響赂蕴。每個(gè)線程其實(shí)也綁定著一個(gè)上下文的類加載器:
- 同一個(gè)命名空間內(nèi)的類是相互可見的。
- 子加載器的命名空間包含所有的父加載器的命令空間舶胀,因此子加載器加載的類能看見父加載器加載的類概说。(eg:AppClassLoader可以看見所有BootstrapClassLoader加載的類,就像java.lang.*下所有的包嚣伐,我們自定義的類都能使用該包空間下的所有的類糖赔。)
- 由父加載器加載的類不能看見子加載器加載的類。(這也算是雙親委托加載的一個(gè)弊端了轩端,若是父加載器想要加載子加載器加載的類如何實(shí)現(xiàn)放典?)
- 如果兩個(gè)加載器之間沒有直接或者間接的父子關(guān)系。那么它們各自加載的類是互不可見的。(像很多三方框架和服務(wù)器,eg:tomcat中奋构,自定義由類的類加載器來加載不同的命名空間的類壳影,那么這些類互不可見,完全解耦弥臼,互不干擾和影響宴咧。注意這與具備父子關(guān)系的父加載器想訪問子加載器加載的類是不同的)
- 當(dāng)兩個(gè)不同命名空間內(nèi)的類互不可見時(shí)候,其實(shí)還是可以采用java的反射機(jī)制來訪問實(shí)例的屬性和方法径缅。
class文件中的信息在JVM如何存儲(chǔ)的掺栅?
Class對(duì)象比較特殊,它雖然是對(duì)象纳猪,但是存放在方法區(qū)里面氧卧。根據(jù)我目前有限知識(shí),參考了其他書籍可知氏堤。當(dāng)JVM啟動(dòng)實(shí)例化引導(dǎo)類加載器和拓展類沙绝,應(yīng)用程序加載器時(shí)候,就會(huì)把包括JDK中重要庫包(eg:rt.jar,resources.jar鼠锈、charsets.jar等)和我們自己寫的java代碼編譯過后闪檬,保存這class具體信息的字節(jié)碼文件中的類信息,都加載到JVM中的方法區(qū)中了脚祟。
包括將類中所有信息(運(yùn)行時(shí)常量谬以,類型信息,字段信息由桌,方法信息为黎,屬性信息,類加載器引用類信息行您,對(duì)應(yīng)class實(shí)例引用)都放置到方法區(qū)铭乾。
就像一個(gè)大的加工類工廠一樣,將包裝了許多原料的麻包娃循,麻袋通過機(jī)器炕檩,人工(就相當(dāng)與類加載器)精密處理,將不同的物料分配到倉房中的不同指定位置捌斧,以備后面需要材料的時(shí)候笛质,進(jìn)行出庫等等。
存放在JVM方法區(qū)中的并不包含類字節(jié)流對(duì)應(yīng)的對(duì)象實(shí)例捞蚂。只是存放類的信息和一些class實(shí)例引用妇押。而對(duì)象實(shí)例大多通常都是創(chuàng)建在heap
堆區(qū)域中了。
class對(duì)象如何獲取和創(chuàng)建姓迅?
類初始化節(jié)點(diǎn)是類加載過程最后一步敲霍,除了上面說的可以自定義類加載器對(duì)二進(jìn)制字節(jié)流自行加載外俊马,其余過程都是JVM來主導(dǎo)和控制運(yùn)行的。到了初始化階段肩杈,才是真正執(zhí)行類中定義的java代碼柴我。(或者是class字節(jié)碼文件中已保存到JVM方法區(qū)中的內(nèi)容)
當(dāng)一系列的類準(zhǔn)備,加載扩然,驗(yàn)證艘儒,解析,初始化后呢与学,在java內(nèi)存中也就有了對(duì)應(yīng)類的Class代表的對(duì)象
彤悔。
在jdk的源碼包:java.lang.Class
中也說到j(luò)ava系統(tǒng)程序在運(yùn)行時(shí)嘉抓,一直對(duì)所有的對(duì)象進(jìn)行所謂的運(yùn)行時(shí)類型標(biāo)識(shí)(靜態(tài)的編譯類型索守,動(dòng)態(tài)的運(yùn)行時(shí)類型),這項(xiàng)信息保存了每個(gè)對(duì)象所屬于的類抑片,JVM通常就可以使用運(yùn)行時(shí)類型標(biāo)識(shí)信息來選擇正確的方法調(diào)用執(zhí)行卵佛,用來保存每個(gè)對(duì)象的類型標(biāo)識(shí)信息的類就是Class類。(在JVM類加載器加載類字節(jié)流的時(shí)候敞斋,也就會(huì)自動(dòng)創(chuàng)建所謂的類型標(biāo)識(shí)截汪,將方法區(qū)域中類的信息都映射保存到Class的類對(duì)象實(shí)例中)
Class類沒有公共的構(gòu)造器,Class對(duì)象是當(dāng)JVM中類加載器加載很多類字節(jié)流和顯示調(diào)用defineClass方法時(shí)自動(dòng)創(chuàng)建好的植捎。
java應(yīng)用程序中的每個(gè)實(shí)例對(duì)象通過obj.getClass()都能得到其對(duì)應(yīng)的Class類衙解。每個(gè)類都有一個(gè)Class對(duì)象,當(dāng)程序運(yùn)行時(shí)候焰枢,JVM首先檢查要加載的類對(duì)應(yīng)的Class對(duì)象是否已經(jīng)加載蚓峦。如果該Class對(duì)象沒有初始化加載,那么JVM會(huì)根據(jù)全限定類名對(duì).class文件在類路徑上進(jìn)行查找济锄,并將.class文件內(nèi)容裝載到Class對(duì)象中
暑椰。
每個(gè)數(shù)組也會(huì)被映射到一個(gè)對(duì)應(yīng)的Class對(duì)象實(shí)例,并且所有具有相同元素類型和維度的數(shù)組都共享該Class對(duì)象荐绝。一般某個(gè)類的Class對(duì)象被載入內(nèi)存一汽,那么就可以用來創(chuàng)建這個(gè)類的所有對(duì)象。(MyObject o = new MyObject())
- 如何可以得到Class對(duì)象低滩?
- 調(diào)用Object類的getClass()方法可以得到對(duì)應(yīng)的Class對(duì)象召夹。
Myobject o;
Class c1 = o.getClass();
- .使用Class類中的靜態(tài)forName()方法得到與全限定名字符串對(duì)應(yīng)的Class對(duì)象。也就是通過反射來獲取恕沫。(JVM類加載器加載监憎,并封裝class信息到Class對(duì)象中)
Class c2 = Class.forName("xx.xx.MyObject");
- 如果T時(shí)一個(gè)java類型(基本類型,引用類型)昏兆,那么可以通過T.class就代表了匹配的類對(duì)象枫虏。
Class cl1 = Student.class;
Class cl2 = int.class;
Class cl3 = String[].class;
那么java.lang.Class有哪些常用的方法妇穴?
-
getName()
一個(gè)Class對(duì)象描述了一個(gè)特定類的屬性,Class類中最常用的方法getName已String形式返回Class 對(duì)象所表示的實(shí)體(類隶债、接口腾它、數(shù)組類、基本類型或 void)名稱死讹。 -
newInstance()
Class還有一個(gè)有用的方法可以為類創(chuàng)建一個(gè)實(shí)例瞒滴,這個(gè)方法叫做newInstance()。例如:
x.getClass.newInstance()赞警,創(chuàng)建了一個(gè)同x一樣類型的新實(shí)例妓忍。newInstance()方法調(diào)用默認(rèn)構(gòu)造器(無參數(shù)構(gòu)造器)初始化新建對(duì)象。 -
getClassLoader()
返回加載該類字節(jié)碼的類加載器愧旦。
總的大體來說世剖,java程序運(yùn)行與OS交互圖如下:(參考自網(wǎng)絡(luò))
好了,對(duì)于class說得差不多了笤虫。從一開始的java源代碼旁瘫,經(jīng)過編譯成*.class字節(jié)碼文件,也詳細(xì)分析了字節(jié)碼里二進(jìn)制對(duì)應(yīng)的含義琼蚯。然后到JVM類加載器加載這些class字節(jié)碼文件酬凳,生成java.lang.Class對(duì)象。這個(gè)流程也流暢的完結(jié)了遭庶,若是有不對(duì)的地方宁仔,再修改。(僅供拋磚引玉.......)
參考:
Java虛擬機(jī)規(guī)范(Java SE 7)中文版(Java_Virtual_Machine_Specification_Java_SE_7)
[深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐].周志明
亦山博客