第十四章:類型信息

運(yùn)行時(shí)類型信息(RTTI)使得你可以在程序運(yùn)行時(shí)發(fā)現(xiàn)和使用類型信息。

Class對(duì)象

每一個(gè)類都有一個(gè)Class對(duì)象。所有的類都是在對(duì)其第一次使用時(shí),動(dòng)態(tài)加載到JVM中。此時(shí),使用類加載器可以生成某個(gè)類的Class對(duì)象。(構(gòu)造器也是類的靜態(tài)方法。)
Class.forName("className")、classObj.getClass():這是取得Class對(duì)象引用的一種方法。
類字面量常量:另外一種方法生成Class對(duì)象的引用。eg,F(xiàn)ancyToy.class。此方法更簡(jiǎn)單,更安全,因?yàn)樵诰幾g時(shí)會(huì)受到檢查,因此不需要置于try語(yǔ)句塊中,更高效。對(duì)于基本數(shù)據(jù)類型,還有一個(gè)標(biāo)準(zhǔn)字段TYPE。為了使用類而做的準(zhǔn)備工作包含三個(gè)步驟:
1.加載:類加載器指向,查找字節(jié)碼,創(chuàng)建Class對(duì)象。
2.鏈接:驗(yàn)證字節(jié)碼,為靜態(tài)域分配存儲(chǔ)空間。若需要,解析這個(gè)類創(chuàng)建的其他類的引用。
3.初始化:若該類具有超類,對(duì)其初始化,執(zhí)行靜態(tài)初始化器和靜態(tài)初始化塊。
但需注意,使用字面量創(chuàng)建Class對(duì)象的引用時(shí),不會(huì)自動(dòng)地初始化該Class對(duì)象。初始化被延遲到對(duì)靜態(tài)方法或者非常數(shù)靜態(tài)域進(jìn)行首次引用時(shí)才執(zhí)行。

boolean.class Boolean.TYPE
char.class Character.TYPE
byte.class Byte.TYPE
short.class Short.TYPE
int.class Integer.TYPE
long.class Long.TYPE
float.class Float.TYPE
double.class Double.TYPE
void.class Void.TYPE

泛化的Class引用:

Class intClass = int.class;
Class<Integer> gIntClass = int.class;
gIntClass = Integer.class; // Same thing
intClass = double.class;
// gIntClass = double.class //Illeagal

向上轉(zhuǎn)型可以編譯通過(guò),但是無(wú)法工作。

Class<Number> gNClass = int.class;

可以使用通配符?。

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

還可以使用范圍通配符:

Class<? extends Number> bounded = int.class;
Class<? super Integer> s = Number.class;

使用泛型語(yǔ)法是為了提供編譯器類型檢查,使語(yǔ)言更加安全。

Class<SonClass> sClass = Son.class;
Son son = Son.newInstance();
Class<? super Son> fClass = sClass.getSuperclass();
// this won't compile
// Class<Father> fClass = sClass.getSuperclass();
// Only produces  
Object obj = fClass.newInstance();
// 有點(diǎn)不懂

使用cast()轉(zhuǎn)型:

Class<House> houseType = House.class;
House h = houseType.cast(b);

RTTI形式

1)傳統(tǒng)的類型轉(zhuǎn)換——“(Shape)”。報(bào)ClassCastException。
2)代表對(duì)象的類型的Class對(duì)象。通過(guò)查詢Class對(duì)象可以獲取運(yùn)行時(shí)所需的信息。
3)instanceof,返回一個(gè)布爾值。class.isInstance(obj)提供了一種動(dòng)態(tài)地測(cè)試對(duì)象的途徑。使用此方法保持了類型的概念,表示某個(gè)類或者某個(gè)類的派生類。而使用eqauls()或者==比較Class對(duì)象時(shí)就沒有考慮繼承

if(x instanceof Dog){}

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

RTTI的使用條件是編譯時(shí)已知這個(gè)類。若在編譯時(shí)無(wú)法獲知這個(gè)對(duì)象所屬的類,就需要使用反射來(lái)檢查匿名對(duì)象的類的可用方法。當(dāng)然,使用反射時(shí)JVM對(duì)于目標(biāo)類的.class文件也是已知的。區(qū)別在于,對(duì)于RTTI來(lái)說(shuō),編譯器在編譯時(shí)打開和檢查.class文件,而反射則是在運(yùn)行時(shí)打開和檢查.class文件。迷惑
類方法提取器:
class.getMethods():返回Method對(duì)象數(shù)組
class.getConstructors():返回Constructor對(duì)象數(shù)組。

動(dòng)態(tài)代理

代理是為了提供額外的或不同的操作,而插入的用來(lái)代替“實(shí)際”對(duì)象的對(duì)象,是個(gè)中間人的角色。代理會(huì)提供和本體一樣的方法,執(zhí)行時(shí)沒有區(qū)別。

//動(dòng)態(tài)代理類
class DynamicProxyHandler implements InvocationHandler{
  private Object proxied;
  public DynamicProxyHandler(Object proxied){
    this.proxied = proxied;
  }
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
     print("do before method");
     return method.invoke(proxied, args);
  }
}
//執(zhí)行動(dòng)態(tài)代理
class SimpleDynamicProxy{
  public static void consumer(Interface iface){
    iface.doSomething();
    iface.somethingElese("bonobo");
  }
  public static void main(String[] args){
    RealObject real = new RealObject();
    consumer(real);
    //使用動(dòng)態(tài)代理調(diào)用
    Interface proxy = (Interface)Proxy.newProxyInstance(
      Interface.class.getClassLoader(),
      new Class[]{ Interface.class},
      new DynamicProxyHandler(real)
    );
    consumer(proxy);
  }
}

空對(duì)象

空對(duì)象是一種設(shè)計(jì)模式,有時(shí)候我們的代碼中為避免 NullPointerException 會(huì)出現(xiàn)很多的對(duì)Null的判斷語(yǔ)句,而這些語(yǔ)句一旦多起來(lái),我們的代碼就會(huì)變的慘不忍睹,因此我們引入了空對(duì)象模式(null object pattern)以此來(lái)使我們的代碼變的更優(yōu)雅一點(diǎn)。
首先創(chuàng)建一個(gè)標(biāo)記接口:

public interface Null{}

這使得可以使用instanceof探測(cè)空對(duì)象。

class Person{
  public final String name;
  public final Strng address;

  public Person(String name, String address){
    this.name = name;
    this.address = address;
  }
  //空對(duì)象
  public static class NullPerson extends Person implements Null{
    private NullPerson() {
      super("None", "None");
      public String toString(){ return "NullPerson";}
    }
  }
  public static final Person NULL = new NullPerson();
}

現(xiàn)在,就可以使用Person.NULL這個(gè)單例對(duì)象作為該類的空對(duì)象。

接口與類型信息

反射可以調(diào)用所有的方法,包括private方法。首先使用class.getDeclaredMethod(methodName)獲取所有聲明的方法,然后method.setAccessible(true),然后method.invoke(obj)觸發(fā)方法。不管是內(nèi)部類還是匿名類,反射都是可以操作的。對(duì)于域來(lái)說(shuō),情況是一樣的,只是final域是修改不了的。

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

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

  • java在運(yùn)行時(shí)識(shí)別對(duì)象和類信息主要有2中方式:1.傳統(tǒng)的RTTI(Run-Time Type Indentifi...
    浩林Leon閱讀 211評(píng)論 0 1
  • 在Java的思想里面,萬(wàn)事萬(wàn)物皆對(duì)象: 其中類也是對(duì)象,所有的類都是一個(gè)Class對(duì)象,可以通過(guò) 類名.class...
    落葉刻痕閱讀 296評(píng)論 0 0
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時(shí)不同JDK版本的...
    高廣超閱讀 16,070評(píng)論 3 83
  • 有個(gè)很要好的朋友勸我開始一段新的戀情,我說(shuō)"都不知道自己應(yīng)該找什么樣的人了”,他默默發(fā)來(lái)一句話“這個(gè)嗎”,頓時(shí)覺得...
    0586e0bf96a6閱讀 291評(píng)論 0 0
  • 《與時(shí)間做朋友》這本書說(shuō)到過(guò),無(wú)論你做什么,時(shí)間都是在流逝,時(shí)間的運(yùn)轉(zhuǎn)不會(huì)取決于任何人,于是李笑來(lái)認(rèn)為時(shí)間不可管理...
    AI賀賀閱讀 469評(píng)論 0 0

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