第十四章:類型信息

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

Class對象

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

Class<Number> gNClass = int.class;

可以使用通配符?。

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

還可以使用范圍通配符:

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

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

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();
// 有點不懂

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

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

RTTI形式

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

if(x instanceof Dog){}

反射:運行時的類信息

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

動態(tài)代理

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

//動態(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í)行動態(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);
    //使用動態(tài)代理調(diào)用
    Interface proxy = (Interface)Proxy.newProxyInstance(
      Interface.class.getClassLoader(),
      new Class[]{ Interface.class},
      new DynamicProxyHandler(real)
    );
    consumer(proxy);
  }
}

空對象

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

public interface Null{}

這使得可以使用instanceof探測空對象。

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

  public Person(String name, String address){
    this.name = name;
    this.address = address;
  }
  //空對象
  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這個單例對象作為該類的空對象。

接口與類型信息

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

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

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

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

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