一、引言
最近在閱讀《Java編程思想》,學習一下java類型信息,現在做一下總結。Java如何讓我們在運行時識別對象和類的信息的。主要有兩種方式:一種是傳統的“RTTI”,它假定我們在編譯時已經知道了所有的類型;另一種是“反射”機制,它允許我們在運行時發現和使用類的信息。
二、Class對象
要理解RTTI的工作原理,首先必須知道類型信息在運行時是如何表示的。這項工作是由稱為Class對象的特殊對象完成的,它包含了與類有關的信息。事實上,Class對象就是用來創建類的所有“常規”對象的。Java使用Class對象來執行RTTI,即使你正在執行的是類似轉型這樣的操作。Class類還擁有大量使用RTTI的其它方式。
類是程序的一部分,每個類都有一個Class對象。換言之,每當編寫并且編譯一個新類,就會產生一個Class對象(更恰當的說,是被保存在一個同名.class文件中)。為了生成這個類的對象,運行這個程序的Java虛擬機(JVM)將使用被稱為“類加載器”的子系統。
類加載器子系統實際上可以包含一條類加載器鏈,但是只有一個原生類加載器。它是JVM實現的一部分。原生類加載器加載的是所謂的可信類,它包括Java API類,它們通常是從本地盤加載的。在這條鏈中,通常不需要額外的類加載器,但是如果你有特殊需求(例如以某種特殊方式加載類,以支持Web服務器應用,或者在網絡中下載類),那么你有一種方式可以掛接這個額外的類加載器。
所有的類都是在對其第一次使用時候,動態加載到JVM中的。當程序創建第一個對類的靜態成員引用時,就會加載這個類。這個證明構造器也是類的靜態方法,即使在構造器之前并沒有使用static關鍵字。因此使用new 操作符創建的新的類對象也會被當做是對類的靜態成員的引用。
三、Class對象的生成方式如下
1.Class.forName("類名字符串")
2.類名.class
3.實例對象.getClass()
四、為了使用類而做的準備工作實際包含三個步驟:
1.加載。 這是由類加載器執行的。該步驟將查找字節碼(通常在classpath所指的路徑中查找,但并非是必需的),并從這些字節碼中創建一個Class對象。
2.鏈接。 在鏈接階段將驗證類中的字節碼,為靜態域分配存儲空間,并且如果必需的話,將解析這個類創建對其他類的所有引用。
3.初始化。 如果該類具有超類,則對其超類初始化,執行靜態初始化器和靜態初始化塊。初始化被延遲到了對靜態方法(構造器隱式的是靜態的)或者非常數靜態域進行首次引用時才執行:
下面是一個初始化的例子
1 import java.util.Random; 2 3 class Initable{ 4 static final int staticFinal = 47 ; 5 static final int staticFinal2 = 6 ClassInitialization.random.nextInt(1000); 7 static { 8 System.out.運行結果如下:
1 After creating Initable ref2 473 Initialzing Initable4 2585 1476 Initializing Initable37 After creating Initable3 ref8 74這個例子展示了:
1.初始化盡可能“惰性”。對initable引用的創建中可以看到, 僅使用.class語法來獲得對類的引用不會發生初始化。但是,為了產生Class引用,Class.forName()立即就進行了初始化,就像在initable3引用創建中看到的。
2.如果一個static final 值是“編譯期常量”,就像Initable.staticFinal那樣,那么這個值不需要對Initable類進行初始化話就可以被讀取。但是,如果只是將一個域設置為static 和final的,還不足以確保這種行為,例如,對Initable.staticFinal2的訪問將強行進行類初始化,因為它不是一個編譯期常量。
3.如果一個static域不是final的,那么在對它進行訪問時,總是要求在它被讀取之前,要先進行連接(為這個域分配存儲空間)和初始化(初始化該存儲空間),就像在對Initable.staticNonFinal的訪問中看到的那樣。
五、Class對象方法概述:
1.Class對象概述
(1)持有RTTI信息
(2)每個類都有一個Class對象,每當編譯一個新類就產生一個Class對象。
(3) Class引用總是指向某個Class對象。Class引用表示的就是它所指向的對象的確切類型,而該對象便是Class類的一個對象。
2.forName()
(1) 獲取Class對象的一個引用,但引用的類還沒有加載(該類的第一個對象沒有生成)就加載了這個類.
(2) 為了產生Class引用,forName()立即就進行了初始化。
3.Object-getClass() 獲取Class對象的一個引用,返回表示該對象的實際類型的Class引用。
4.getName() 獲取全限定的類名(包括包名),即類的完整名字。
5.getSimpleName() 獲取類名(不包括包名)
6.getCanonicalName() 獲取全限定的類名(包括包名)
7.isInterface() 判斷Class對象是否是表示一個接口
8.getInterface() 返回Class對象,表示Class對象所引用的類所實現的所有接口。
9.getSupercalss() 返回Class對象,表示Class對象所引用的類所繼承的直接基類。應用該方法可在運行時發現 一個對象完整的繼承結構。
10.newInstance() 返回一個Oject對象,是實現“虛擬構造器”的一種途徑。“虛擬構造器”:我不知道你的確切的 類型,但無論如何都要正確創建你自己。用該方法創建的類,必須帶有默認的構造器。
11.cast() 接受一個對象為參數,并將其轉型為Class引用的類型。該法一般是在無法使用普通轉型的情況下使用。
12.getClassLoader() 返回該類的類加載器。
13.getComponentType() 返回表示數組組件類型的Class。
14.isArray() 判定此 Class 對象是否表示一個數組類。
15.泛化的Class引用
1)實現方法:使用通配符“?”。
2)Class<?>優于Class,即便他們是等價的。
3)Class<?>的好處是明確地告訴編譯器你選擇了非具體的類版本,而不是由于碰巧或者疏忽而使用了一個非具體的類引用。
4)創建一個范圍:創建一個Class引用 ,使它被限定為某種類型<className>;或該類型的任何子類型,< ? extends superClass>;或者該類型的超類,< ? super super sunClassName>
新聞熱點
疑難解答