第十四章:類型信息

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

Class對象

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

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

向上轉型可以編譯通過,但是無法工作。

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()轉型:

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

RTTI形式

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

if(x instanceof Dog){}

反射:運行時的類信息

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

動態代理

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

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

空對象

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

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();
}

現在,就可以使用Person.NULL這個單例對象作為該類的空對象。

接口與類型信息

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

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

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