类型信息
1、java主要有兩種方式在運(yùn)行時識別對象和類的信息:RTTI和“反射”機(jī)制。
2、類加載器系統(tǒng)實(shí)際上可以包含一條類加載器鏈,但是只有一個原生態(tài)加載器,它是JVM實(shí)現(xiàn)的一部分。原生態(tài)加載器加載的是所謂的可信類,包括Java API,它們通常都是從本地盤加載的。在這條鏈中,通常不需要添加額外的類加載器,但是如果你有需求,那么你有一種方式可以掛載額外的類加載器。
3、所有的類都是在對其第一次使用時,動態(tài)加載到JVM中。java程序再它開始運(yùn)行之前并非完全加載,其各個部分是在必需時才加載。
4、使用Class.forName()加載類時,必需使用全限定名(包括包名)。
5、java還提供了“類字面常量”來獲得Class對象的引用。即類A獲取Class引用的方法為A.class。這樣做不僅簡單,安全(因?yàn)樵诰幾g期是就會檢查),而且比forName的方法高效。對于基本類型的包裝類,還有一個標(biāo)準(zhǔn)字段TYPE指向Class對象的引用。boolean.class等價于Boolean.TYPE。
6、 為了使用類而做的準(zhǔn)備有三個步驟:
- 加載:由類加載器進(jìn)行,該步驟將查找字節(jié)碼,并從字節(jié)碼中創(chuàng)建Class對象引用。
- 鏈接:驗(yàn)證類中的字節(jié)碼,為靜態(tài)域分配存儲空間,并且如果必須的話,將解析這個類創(chuàng)建的對其他類的所有引用。
- 初始化:如果該類具有超類,則對其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。
- 初始化有效地實(shí)現(xiàn)了盡可能的“惰性”。僅使用.class不會觸發(fā)類的初始化。而調(diào)用Class.forName會導(dǎo)致類初始化。(比如Initable.class和Class.forName("com.yanguang.Initable3"))
- 如果一個類的變量是static final的
- 這個變量的值是編譯器常量:這個值可以在類不被初始化時就可以讀取。(Initable.staticFinal)
- 這個變量的值動態(tài)獲得(比如通過隨機(jī)函數(shù)生成),那么對這個值得調(diào)用會導(dǎo)致類的初始化。(Initable.staticFinal2)
- 如果一個static域不是final的,那么在訪問它時,總是要求在它被讀取前,先進(jìn)行鏈接(分配空間)和初始化(初始化該空間)。(Initable2.staticNonFinal)
7、泛化的Class引用。向Class引用添加泛型語法的原因僅僅是為了提供編譯期類型檢查。
Class intClass = int.class; intClass = double.class; //編譯通過 Class<Integer> genericIntClass = int.class; // genericIntClass = double.class; // 編譯報(bào)錯。有時為了放松校驗(yàn)的范圍,可以使用泛型的特性? extends
// Class<Number> genericNumberClass = int.class; Class<? extends Number> bounded = int.class; bounded = double.class;因?yàn)镮nteger Class對象不是Number Class對象的子類。
8、instanceof 和isInstance()生成的結(jié)果完全一樣,equals()和==也一樣。另外,instanceof保持了類型的概念,它指的是“你是這個類嗎?或者你是這個類的派生類嗎?”而如果用==將會比較實(shí)際的Class對象,就沒考慮繼承-它或者是這個確切的類型,或者不是。
9、當(dāng)通過反射與一個未知類型的對象打交道時,JVM只是簡單地檢查這個對象,看它屬于哪個特定的類(就像RTTI那樣)。在真正調(diào)用它之前,必須先加載它的Class對象。因此,它的class文件對于JVM來說,必須是可以獲取的,要么是在本地機(jī)器,要么是在網(wǎng)絡(luò)上。所以RTTI和反射之間真正的區(qū)別只在于,對于RTTI來說,編譯器在編譯時打開和檢查.class文件。而對于反射來說,.class文件在編譯時是不可獲取的,所以是在運(yùn)行時打開和檢查.class文件。
10、代理是基本的設(shè)計(jì)模式之一,它是你為了提供額外的操作或不同的操作,而插入的用來代替實(shí)際對象的對象。Java的動態(tài)代理可以動態(tài)地創(chuàng)建代理并動態(tài)地處理對所調(diào)方法的調(diào)用。
- 動態(tài)代理得實(shí)現(xiàn)InvocationHandler接口,其中有invoke方法,參數(shù)分別為代理對象,方法,參數(shù)。
- invoke()方法中傳遞進(jìn)來代理對象,以防你需要區(qū)分請求的資源。
- 通常,會用Proxy.newProxyInstance(Interface.class.getClassLoader(),new Class[]{Interface.class}, new DynamicProxyHandler(realObject))的方法生成代理類,并用被代理對象的接口指向代理類,然后在方法中用Method.invoke()將請求轉(zhuǎn)發(fā)給被代理對象,并傳入必須的參數(shù)。
11、使用interface關(guān)鍵字的一種重要目標(biāo)就是允許程序員隔離構(gòu)件,進(jìn)而降低耦合度。但是有了instanceof之后,你就能知道接口引用所指向的具體對象,從而向下轉(zhuǎn)型,這就會使得代碼和具體對象的耦合提高,這是我們所不希望看到的。對于這種情況,最簡單的方式是對接口的實(shí)現(xiàn)類使用包訪問權(quán)限,這樣在包外部的客戶端就不能看到它們了。
class C implements A{ } public class HiddenC{ pubic static A makeA(){return new C();} }- 但是通過反射,你仍舊可以到達(dá)并調(diào)用所有方法,即使是private方法。
轉(zhuǎn)載于:https://www.cnblogs.com/kejicjk/p/7039904.html
總結(jié)
- 上一篇: 皖事通怎么更改注册人信息
- 下一篇: Eclipse新建java类的时候,自动