《Thinking in Java》學(xué)習(xí)筆記——14章類型信息

Class對象

1.每當(dāng)編寫并編譯了一個(gè)新類,就會產(chǎn)生一個(gè)Class對象(更恰當(dāng)?shù)卣f,是被保存在一個(gè)同名的.class文件中)。為了生成這個(gè)類的對象,運(yùn)行這個(gè)程序的Java虛擬機(jī)將使用被稱為“類加載器”的子系統(tǒng)。
2.所有的類都是在對其第一次使用時(shí),動(dòng)態(tài)加載到JVM中的。當(dāng)程序創(chuàng)建第一個(gè)對類的靜態(tài)成員的引用時(shí),就會加載這個(gè)類。這個(gè)證明構(gòu)造器也是類的靜態(tài)方法,因此使用new操作符創(chuàng)建類的新對象也會被當(dāng)作對類的靜態(tài)成員的引用。
3.Java程序在它開始運(yùn)行之前并非被完全加載,其各個(gè)部分是在必需時(shí)才加載的。
4.Class對象僅在需要的時(shí)候才被加載,static初始化是在類加載時(shí)進(jìn)行的。
5.無論如何,只要你想在運(yùn)行時(shí)使用類型信息,就必需首先獲得對恰當(dāng)?shù)腃lass對象的引用。Class.forName()就是實(shí)現(xiàn)此功能的便捷途徑,因?yàn)槟悴恍枰獮榱双@得Class引用而持有該類型的對象。如果已經(jīng)擁有了一個(gè)類型的對象,那就可以通過調(diào)用getClass()方法來獲取Class引用。
6.getName()來產(chǎn)生全限定的類名;getSimpleName()來產(chǎn)生不含包名的類名;getCanonicalName()來產(chǎn)生全限定的類名;isInterface()方法可以告訴你這個(gè)Class對象是否表示一個(gè)接口;getInterfaces()方法返回的是Class對象,它們表示在Class對象中所包含的接口;getSuperclass()方法可用來查詢基類,將返回用來進(jìn)一步查詢的Class對象;newInstance()可用來創(chuàng)建Class對象所對應(yīng)的類,但必須帶有默認(rèn)構(gòu)造器。

一.類字面常量

1.Java還可以使用類字面常量——“.class”的形式來生成對Class對象的引用。
2.類字面常量不僅可以應(yīng)用于普通的類,也可以應(yīng)用于接口、數(shù)組以及基本數(shù)據(jù)類型。
3.與通過Class中的方法創(chuàng)建對Class對象的引用不同的是,通過“.class”的方法創(chuàng)建不會自動(dòng)地初始化該Class對象,初始化被延遲到了對靜態(tài)方法(包括構(gòu)造器)或者非常數(shù)靜態(tài)域進(jìn)行首次引用的時(shí)候才會執(zhí)行。
4.使用類需要包括的三個(gè)步驟:
(1).加載,這是由類加載器執(zhí)行的。該步驟將查找字節(jié)碼,并從這些字節(jié)碼中創(chuàng)建一個(gè)Class對象。
(2).鏈接。在鏈接階段將驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配存儲空間,并且如果必須的話,將解析這個(gè)創(chuàng)建的對其他類的引用。
(3).初始化。如果該類具有超類,則對其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。
5.如果一個(gè)static final值是“編譯期常量”,那么這個(gè)值不需要對類進(jìn)行初始化就可以被讀取。如果一個(gè)static域不是final的,那么在對它訪問時(shí),總是要求在它被讀取之前,要先進(jìn)行鏈接(為這個(gè)域分配存儲空間)和初始化(初始化該存儲空間)。

class Initable {
    static final int staticFinal = 47;//static final的編譯期常量,使用時(shí)不用初始化
    static final int staticFinal2 = ClassInitaialization.rand.nextINt(1000);//雖然是static final的,但是不是編譯期常量,使用時(shí)需要初始化
    static int staticFinal3 = 47;//不是final的,使用時(shí)需要進(jìn)行初始化
}
二.泛化的Class引用

1.Class引用表示的就是它所指向的對象的確切類型,而該對象便是Class類的一個(gè)對象。
2.使用泛型語法,實(shí)現(xiàn)對Class引用所指向的Class對象的類型進(jìn)行限定。

public class GenericClassReference {
    public static void main(String...args) {
        Class intClass = int.class;
        Class<Integer> genericIntClass = int.class;
        genericIntClass = Integer.class; // Same thing
        intClass = double.class; // Success
        //genericIntClass = double.class; // Illegal
    }
}

為了在使用泛化的Class引用時(shí)放松限制,可以使用通配符。

Class<?> intClass = int.class;
intClass = double.class;

3.當(dāng)將泛型語法用于Class對象的時(shí)候:newInstance()將返回該對象的確切類型,而不僅僅只是基本的Object

三.新的轉(zhuǎn)型語法

1.JavaSE5中添加了用于Class引用的轉(zhuǎn)型語法,即cast()方法:

Building b = new House();
Class<House> houseType = House.class;
House h = houseType.cast(b); // 與 h = (House) b; 效果相同

類型轉(zhuǎn)換前先做檢查

1.使用關(guān)鍵字instanceof,它返回一個(gè)布爾值,告訴我們對象是不是某個(gè)特定類型的實(shí)例:

if (x instanceof Dog)
    ((Dog) x).bark();

進(jìn)行向下轉(zhuǎn)型前,如果沒有其他信息告訴你對象是什么類型,那么使用instanceof是非常重要的,否則會得到一個(gè)ClassCastException異常。
2.對instanceof有比較嚴(yán)格的限制:只可將其與命名類型進(jìn)行比較,而不能與Class對象作比較。如果程序中編寫了許多的instanceof表達(dá)式,就說明你的設(shè)計(jì)可能存在瑕疵。

一.動(dòng)態(tài)的instanceof

1.isInstance()方法不用與命名類型進(jìn)行比較,而可以直接與Class對象進(jìn)行比較

Pet pet = new Dog();
if (pet.isInstance(Dog.class)))
    ((Dog) pet).bark();

2.使用isAssignableFrom()來執(zhí)行運(yùn)行時(shí)檢查,以校驗(yàn)?zāi)銈鬟f的對象確實(shí)屬于我們感興趣的繼承結(jié)構(gòu)。

二.instanceof與Class的等價(jià)性

1.在查詢類型信息的時(shí)候,以instanceofisInstance()的形式與直接比較Class對象有一個(gè)很重要的區(qū)別。instanceof保持了類型的概念,它指的是“你是這個(gè)類嗎,或者你是這個(gè)類的派生類嗎?”而如果用“==”比較實(shí)際的Class對象,就沒有考慮繼承——它或者是這個(gè)確切的類型,或者不是。

反射:運(yùn)行時(shí)的類信息

1.Class類與java.lang.reflect類庫一起對反射的概念進(jìn)行了支持,該類庫包括了Field、Method以及Constructor類(每個(gè)類都實(shí)現(xiàn)了Member接口)。這些類型的對象是由JVM在運(yùn)行時(shí)創(chuàng)建的用以表示未知類里對應(yīng)的成員。
2.RTTI和反射之間真正的區(qū)別只在于,對RTTI來說,編譯器在編譯時(shí)打開和檢查.class文件。而對于反射機(jī)制來說,.class文件在編譯時(shí)是不可獲取的,所以是在運(yùn)行時(shí)打開和檢查.class文件。

類方法提取器

1.ClassgetMethods()getConstructors()方法分別返回Method對象的數(shù)組和Constructor對象的數(shù)組。
2.Class.forName()生成的結(jié)果在編譯時(shí)是不可知的,因此所有的方法特征簽名信息都是在執(zhí)行時(shí)被提取出來的。反射機(jī)制提供了足夠的支持,使得能夠創(chuàng)建一個(gè)編譯時(shí)完全未知的對象,并調(diào)用此對象的方法。

接口與類型信息

1.通過使用反射,即使實(shí)現(xiàn)包的訪問權(quán)限,仍舊可以到達(dá)并調(diào)用所有方法,甚至是private方法。如果知道方法名,就可以在其Method對象上調(diào)用setAccessible(true),然后通過invoke()方法來使用該方法。
2.final域?qū)嶋H上在遭遇修改時(shí)是安全的。運(yùn)行時(shí)系統(tǒng)會在不拋異常的情況下接受任何修改嘗試,但實(shí)際上不會發(fā)生任何修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,652評論 18 399
  • (一)Java部分 1、列舉出JAVA中6個(gè)比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨(dú)云閱讀 7,254評論 0 62
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運(yùn)行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,810評論 0 11
  • 牽著小狗漫步在初春的街道上,隨處可見青綠的嫩冬青,當(dāng)然我并不知道它是不是冬青,只是感覺像罷了。我忍不住想去摘下一...
    與你北郊閱讀 424評論 0 0

友情鏈接更多精彩內(nèi)容