多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > Java反射探索-從類加載說起

Java反射探索-從類加載說起

來源:程序員人生   發(fā)布時間:2016-04-13 08:06:13 閱讀次數(shù):2436次

        摘要:本文主要講了Java類加載的機(jī)制,這是學(xué)習(xí)反射的入門基礎(chǔ)。


1、類加載

JVM和類

      當(dāng)我們調(diào)用Java命令運行某個Java程序時,該命令將會啟動1條Java虛擬機(jī)進(jìn)程,不管該Java程序有多么復(fù)雜,該程序啟動了多少個線程,它們都處于該Java虛擬機(jī)進(jìn)程里。正如前面介紹的,同1個JVM的所有線程、所有變量都處于同1個進(jìn)程里,它們都使用該JVM進(jìn)程的內(nèi)存區(qū)。當(dāng)系統(tǒng)出現(xiàn)以下幾種情況時,JVM進(jìn)程將被終止:

1、程序運行到最后正常結(jié)束。
2、程序運行到使用System.exit()或Runtime.getRuntime().exit()代碼結(jié)束程序。
3、程序履行進(jìn)程中遇到未捕獲的異常或毛病而結(jié)束。
3、程序所在平臺強(qiáng)迫結(jié)束了JVM進(jìn)程。
從上面的介紹可以看出,當(dāng)Java程序運行結(jié)束時,JVM進(jìn)程結(jié)束,該進(jìn)程在內(nèi)存中狀態(tài)將會丟失。

類的生命周期

類的加載/類初始化

     當(dāng)程序主動使用某個類時,如果該類還未被加載到內(nèi)存中,系統(tǒng)會通過加載、連接、初始化3個步驟來對該類進(jìn)行初始化,如果沒成心外,JVM將會連續(xù)完成這3個步驟,所以有時也把這3個步驟統(tǒng)稱為類加載或類初始化。

加載:查找并加載類的2進(jìn)制數(shù)據(jù)

     1、通過1個類的全限定名來獲得定義此類的2進(jìn)制字節(jié)流。
2、將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)。
3、在java堆中生成1個代表這個類的java.lang.Class對象,作為方法區(qū)這些數(shù)據(jù)的訪問入口。

注意:將編譯后的java類文件(也就是.class文件)中的2進(jìn)制數(shù)據(jù)讀入內(nèi)存,并將其放在運行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi),然后再堆區(qū)創(chuàng)建1個Java.lang.Class對象,用來封裝類在方法區(qū)的數(shù)據(jù)結(jié)構(gòu)。即加載后終究得到的是Class對象,并且更加值得注意的是:該Java.lang.Class對象是單實例的,不管這個類創(chuàng)建了多少個對象,他的Class對象時唯1的!
連接:

        1、驗證:確保被加載的類的正確性
        2、準(zhǔn)備:為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默許值
        3、解析:把類中的符號援用轉(zhuǎn)換為直接援用。
初始化:為類的靜態(tài)變量賦予正確的初始值。

注意:連接和初始化階段,其實靜態(tài)變量經(jīng)過了兩次賦值:第1次是靜態(tài)變量類型的默許值;第2次是我們真正賦給靜態(tài)變量的值。

我簡單畫了個圖,其進(jìn)程以下:


 類加載指的是將類的class文件讀入內(nèi)存,并為之創(chuàng)建1個java.lang.Class對象,也就是說當(dāng)程序中使用任何類時,系統(tǒng)都會為之建立1個java.lang.Class對象。事實上,每一個類是1批具有相同特點的對象的抽象(或說概念),而系統(tǒng)中所有的類,它們實際上也是對象,它們都是java.lang.Class的實例。

    加載由類加載器完成,類加載器通常由JVM提供,這些類加載器也是我們前面所有程序運行的基礎(chǔ),JVM提供的這些類加載器通常被稱為系統(tǒng)類加載器。除此以外,開發(fā)者可以通過繼承ClassLoader基類來創(chuàng)建自己的類加載器。


通過使用不同的類加載器,可以從不同來源加載類的2進(jìn)制數(shù)據(jù),通常有以下幾種來源:

1、從本地文件系統(tǒng)來加載class文件,這是絕大部份示例程序的類加載方式。
2、從JAR包中加載class文件,這類方式也是很常見的,前面介紹JDBC編程時用到的數(shù)據(jù)庫驅(qū)動類就是放在JAR文件中,JVM可以從JAR文件中直接加載該class文件。
3、通過網(wǎng)絡(luò)加載class文件。
4、把1個Java源文件動態(tài)編譯、并履行加載。


類加載器通常不必等到“首次使用”該類時才加載該類,Java虛擬機(jī)規(guī)范允許系統(tǒng)預(yù)先加載某些類。


Java程序?qū)︻惖氖褂梅绞?br /> 主動使用
1、創(chuàng)建類的實例
2、方法某個類或接口的靜態(tài)變量,或?qū)υ撿o態(tài)變量賦值
3、調(diào)用類的靜態(tài)方法
4、反射(如 Class.forName(“com.itzhai.Test”))
5、初始化1個類的子類
6、Java虛擬機(jī)啟動時被標(biāo)明為啟動類的類(Main Class)

被動使用
除以上6中方式,其他對類的使用都是被動使用,都不會致使類的初始化。類的初始化時機(jī)正是java程序?qū)︻惖氖状沃鲃邮褂茫?br /> 所有的Java虛擬機(jī)實現(xiàn)必須在每一個類或接口被Java程序“首次主動使用”時才初始化它們。


對象初始化
在類被裝載、連接和初始化,這個類就隨時都可能使用了。對象實例化和初始化是就是對象生命的起始階段的活動,在這里我們主要討論對象的初始化工作的相干特點。
Java 編譯器在編譯每一個類時都會為該類最少生成1個實例初始化方法--即"()" 方法。此方法與源代碼中的每一個構(gòu)造方法相對應(yīng),如果類沒有明確地聲明任何構(gòu)造方法,編譯器則為該類生成1個默許的無參構(gòu)造方法,這個默許的構(gòu)造器僅僅調(diào)用父類的無參構(gòu)造器,與此同時也會生成1個與默許構(gòu)造方法對應(yīng)的 "()" 方法.
通常來講,() 方法內(nèi)包括的代碼內(nèi)容大概為:調(diào)用另外一個() 方法;對實例變量初始化;與其對應(yīng)的構(gòu)造方法內(nèi)的代碼。
如果構(gòu)造方法是明確地從調(diào)用同1個類中的另外一個構(gòu)造方法開始,那它對應(yīng)的() 方法體內(nèi)包括的內(nèi)容為:1個對本類的() 方法的調(diào)用;對利用構(gòu)造方法內(nèi)的所有字節(jié)碼。
如果構(gòu)造方法不是通過調(diào)用本身類的其它構(gòu)造方法開始,并且該對象不是 Object 對象,那() 法內(nèi)則包括的內(nèi)容為:1個對父類() 方法的調(diào)用;對實例變量初始化方法的字節(jié)碼;最后是對應(yīng)構(gòu)造子的方法體字節(jié)碼。
如果這個類是 Object,那末它的() 方法則不包括對父類() 方法的調(diào)用。


2、Class.forName、實例對象.class(屬性)、實例對象getClass()的區(qū)分

1、相同點:
通過這幾種方式,得到的都是Java.lang.Class對象(這個是上面講到的類在加載時取得的終究產(chǎn)物)
例如:

package com.lin; /** * 功能概要: * * @author linbingwen * @since 2015年10月20日 */ public class people { /** * @author linbingwen * @since 2015年10月20日 * @param args */ public static void main(String[] args) throws Exception { System.out.println("..............使用不同的方式加載類..................."); System.out.println(people.class);//通過類.class取得Class對象 people a = new people(); System.out.println(a.getClass());//通過 實例名.getClass()取得Class對象 System.out.println(Class.forName("com.lin.people"));//通過Class.forName(全路徑)取得Class對象 System.out.println("..............使用不同的方式創(chuàng)建對象..................."); System.out.println(a);//使用不同的方式創(chuàng)建對象 System.out.println(people.class.newInstance()); System.out.println(a.getClass().newInstance()); System.out.println(Class.forName("com.lin.people").newInstance()); } }

結(jié)果:


從上面可以看到不同的方式加載類。其實這1進(jìn)程只產(chǎn)生1次!

2、區(qū)分:

下面用1個實例來講說它們的區(qū)分

以下新建1個類

package com.lin; /** * 功能概要: * * @author linbingwen * @since 2015年10月20日 */ public class Cat { static { System.out.println("生成了1只貓"); } }

然后開始使用:

package com.lin; /** * 功能概要: * * @author linbingwen * @since 2015年10月20日 */ public class CatTest { /** * @author linbingwen * @since 2015年10月20日 * @param args */ public static void main(String[] args) throws Exception{ System.out.println("---------------Cat.class開始------------------"); System.out.println(Cat.class);//通過類.class取得Class對象 System.out.println("---------------Cat.class結(jié)束------------------"); System.out.println("---------------Class.forName開始------------------"); System.out.println(Class.forName("com.lin.Cat"));//通過Class.forName(全路徑)取得Class對象 System.out.println("---------------Class.forName結(jié)束------------------"); System.out.println("---------------cat.getClass()開始------------------"); Cat cat = new Cat(); System.out.println(cat.getClass());//通過Class.forName(全路徑)取得Class對象 System.out.println("---------------cat.getClass()結(jié)束------------------"); } }
輸出結(jié)果:

如果,將Class.forName()去掉:

以下:

package com.lin; /** * 功能概要: * * @author linbingwen * @since 2015年10月20日 */ public class CatTest { /** * @author linbingwen * @since 2015年10月20日 * @param args */ public static void main(String[] args) throws Exception{ System.out.println("---------------Cat.class開始------------------"); System.out.println(Cat.class);//通過類.class取得Class對象 System.out.println("---------------Cat.class結(jié)束------------------"); // System.out.println("---------------Class.forName開始------------------"); // System.out.println(Class.forName("com.lin.Cat"));//通過Class.forName(全路徑)取得Class對象 // System.out.println("---------------Class.forName結(jié)束------------------"); System.out.println("---------------cat.getClass()開始------------------"); Cat cat = new Cat(); System.out.println(cat.getClass());//通過Class.forName(全路徑)取得Class對象 System.out.println("---------------cat.getClass()結(jié)束------------------"); } }

結(jié)果又變成:


所以,可以得出以下結(jié)論:

1)Class cl=Cat.class; JVM將使用類Cat的類裝載器,將類A裝入內(nèi)存(條件是:類A還沒有裝入內(nèi)存),不對類A做類的初始化工作.返回類A的Class的對象
2)Class cl=對象援用o.getClass();返回援用o運行時真正所指的對象(由于:兒子對象的援用可能會賦給父對象的援用變量中)所屬的類的Class的對象 ,如果還沒裝載過,會進(jìn)行裝載。
3)Class.forName("類名"); 裝入類A,并做類的初始化(條件是:類A還沒有裝入內(nèi)存)

3、new和newInstance()

從JVM的角度看,我們使用關(guān)鍵字new創(chuàng)建1個類的時候,這個類可以沒有被加載。但是使用Class對象的newInstance()方法的時候,就必須保證:

1、這個類已加載;

2、這個類已連接了。而完成上面兩個步驟的正是Class的靜態(tài)方法forName()所完成的,這個靜態(tài)方法調(diào)用了啟動類加載器,即加載 java API的那個加載器。 

現(xiàn)在可以看出,Class對象的newInstance()(這類用法和Java中的工廠模式有著異曲同工之妙)實際上是把new這個方式分解為兩步,即首先調(diào)用Class加載方法加載某個類,然后實例化。這樣分步的好處是不言而喻的。我們可以在調(diào)用class的靜態(tài)加載方法forName時取得更好的靈活性,提供給了1種降耦的手段。 

Class.forName().newInstance()和通過new得到對象的區(qū)分


1、使用newInstance可以解耦。使用newInstance的條件是,類已加載并且這個類已連接,這是正是class的靜態(tài)方法forName()完成的工作。newInstance實際上是把new 這個方式分解為兩步,即,首先調(diào)用class的加載方法加載某個類,然后實例化。

2、newInstance: 弱類型。低效力。只能調(diào)用無參構(gòu)造。 new: 強(qiáng)類型。相對高效。能調(diào)用任何public構(gòu)造。 

3、newInstance()是實現(xiàn)IOC、反射、面對接口編程和依賴顛倒等技術(shù)方法的必定選擇,new只能實現(xiàn)具體類的實例化,不合適于接口編程。 

4、 newInstance() 1般用于動態(tài)加載類。

5、Class.forName(“”).newInstance()返回的是object 。

6、newInstance( )是1個方法,而new是1個關(guān)鍵字;

注:1般在通用框架里面用的就是class.forName來加載類,然后再通過反射來調(diào)用其中的方法,比方Tomcat源碼里面,這樣就避免了new關(guān)鍵字的耦合度,還有讓不同的類加載器來加載不同的類,方便提高類之間的安全性和隔離性.

生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 亚洲在线观看免费视频 | 欧美日韩国产精品自在自线 | 久久久国产成人精品 | 日韩精品久久一区二区三区 | 欧美日韩国产最新一区二区 | 亚洲美女高清aⅴ视频免费 亚洲美女激情视频 | a级亚洲片精品久久久久久久 | 亚洲天堂网在线播放 | 亚洲最大的黄色网址 | 欧美最猛性xxxxx短视频 | 可以在线观看的黄色网址 | freexxx性欧美hd| 亚洲欧美精选 | 在线免费日本 | 国内性经典xxxxx | 伊人成综合 | 亚洲国产精品高清在线一区 | 秋霞免费理论片在线观看午夜 | 狠狠躁天天躁夜夜躁婷婷 | 久久精品国产2020 | jizz在线观看视频 | 欧美一级毛片高清免费观看 | 欧美一区不卡二区不卡三区 | 亚洲精品国产啊女成拍色拍 | 亚洲区欧美中文字幕久久 | 亚洲精品在线第一页 | 手机看片日韩欧美 | 全国男人的天堂网站 | 最新国产福利在线观看 | 日韩欧美一区二区久久 | 中文字幕精品一区二区2021年 | 国产精品ⅴ视频免费观看 | 在线精品视频成人网 | 精品久久久久久中文字幕女 | 一区二区三区高清不卡 | 欧美xxxxx九色视频免费观看 | 国产性夜夜春夜夜爽30 | 亚洲综合影视 | 精品免费 | 国产免费网站看v片元遮挡 国产免费午夜a无码v视频 | 色哟哟tv |