RTTI

Java中有兩種方式讓咱們在運行時識別對象的類的信息:傳統的RTTI(Run-Time Type Identification)和反射。數組

Class對象

Class對象包含了與類有關的信息,用來建立類的全部「常規」對象的特殊對象。每個類都有一個Class對象。dom

建立Class對象的引用

能夠用兩種方式來建立Class對象引用:Class.forName()和類字面常量。spa

 

建立一個類Farther:code

 class Farther { Farther() {} static {System.out.println("loading farther");} } 對象

用Class.forName()來建立引用,forName()的參數必須是包含報名的全限定名,而且在找不到類時會拋出ClassNotFoundException:blog

Class c = null;
try {
    c = Class.forName("typeinfo.toys.Farther");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
System.out.println("已建立引用");
/*
 * 輸出:
 * loading farther
 * 已建立引用
 */

 用類字面常量建立引用:繼承

Class c = null;
c = Farther.class;
/*
 * 輸出:
 * 已建立引用
 */

 

能夠發如今使用類字面常量時沒有執行Farther類的靜態初始化塊,這是由於初始化被延遲到了對靜態方法或很是數靜態域(被static 和 final修飾的常量域)進行首次引用時才執行。接口

class Farther {
    static final int test = 1;
    static final int test2 = (int)(Math.random()*10)+1;
    Farther() {}
    static {System.out.println("loading farther");}
}
public class Test {
    public static void main(String[] args) {
        Class c = Farther.class;
        System.out.println(Farther.test);
        System.out.println(Farther.test2);
    }
}
/*
 * 輸出:
 * 1
 * loading farther
 * 7
 */

Class類的一些經常使用方法

package tests;

interface inte1 {}
interface inte2 {}
interface inte3 {}

class Farther {
    static final int test = 1;
    static final int test2 = (int)(Math.random()*10)+1;
    Farther() {}
    static {System.out.println("loading farther");}
}

class Child extends Farther implements inte1, inte2 {
    Child() {}
    static {System.out.println("loading child");}
}

public class ThinkInJavaTest {
    static void print(Object obj) {System.out.println(obj);}
    
    public static void main(String[] args) {
        Class child = null;
        try {
            child = Class.forName("tests.Child");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        print("Child getName: " + child.getName());
        print("Child getSimpleName: " + child.getSimpleName());
        print("Child getCanonicalName: " + child.getCanonicalName());
        for(Class inte : child.getInterfaces()) 
            print(inte.getSimpleName());
        Class farther = child.getSuperclass();
        Object obj = null;
        try {
            obj = farther.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        print(obj.getClass().getSimpleName());
        
        Child[] a = new Child[10];
        print(a.getClass().getName());
        print(a.getClass().getSimpleName());
        print(a.getClass().getCanonicalName());
    }
}
/*
 * 輸出:
 * loading farther
 * loading child
 * Child getName: tests.Child
 * Child getSimpleName: Child
 * Child getCanonicalName: tests.Child
 * inte1
 * inte2
 * Farther
 * [Ltests.Child;
 * Child[]
 * tests.Child[]
 */

getSimpleName()返回不帶包名的類名,getName()和getCanonicalName()返回全限定名。最後幾行代碼演示了getName()和getCanonicalName()用於數組時的不一樣。get

getInterfaces()以數組形式返回這個類所表明的實體(類,接口,基本數據類型或void)實現的接口的Class對象。io

getSuperclass()返回這個類所表明的實體(類,接口,基本數據類型或void)的超類。

newInstance()新建一個此類型的實例,這個類必須有無參構造器;若是這個Class表明抽象類、接口、基本類型、數組、void中的其中一個或者沒有無參構造器則會拋出InstantiationException。

 

Class引用和泛型

 咱們能夠經過泛型語法來限定Class引用所指向的Class對象的類型的類型。

Class a = Child.class;
Class<?> b = Child.class;
Class<Farther> c = Farther.class;
Class<? extends Farther> d = Child.class;
Class<? super Child> e = Farther.class;
a = Farther.class;
b = Farther.class;
d = Farther.class;
e = Child.class;

其中Class<?> 與普通的Class等價,可是普通的Class會出現警告。

Child雖然是Farther的子類可是不能使用 c = Child.class 由於 Child Class不是Farther Class的子類對象。

 

下面演示了對不一樣泛型的Class引用調用newInstance所返回的類型。

try{
    Object obj = a.newInstance();
    obj = b.newInstance();
    Farther far = c.newInstance();
    far = d.newInstance();
    obj = e.newInstance();
} catch(Exception ex) {
    print("newInstance 失敗");
}

 

類型檢查

instanceof

關鍵字instanceof返回一個布爾值,告訴咱們是否是某個特定類型的實例。

Child c = new Child();
if(c instanceof Child) print("is a child");
if(c instanceof Farther) print("is a farther");
/*
loading farther
loading child
child
farther
*/

可是instanceof只能使用類型名稱,這樣的話在一些狀況下須要寫不少的instanceof。

動態的instanceof

 也可使用Class對象的isInstance()方法:

public class Test {
    static void print(Object obj) {System.out.println(obj);}
    
    static boolean judge(Class c, Object obj) {
        return c.isInstance(obj);
    }
    
    public static void main(String[] args) {
        Class<Farther> fc = Farther.class;
        Child ch = new Child();
        print(judge(fc, ch));
        
    }
}
/*
loading farther
loading child
true
*/

這樣就再也不須要寫不少的instanceof了

直接比較Class對象

固然也能夠直接比較Class對象:

public class Test {
    static void print(Object obj) {System.out.println(obj);}
    
    public static void main(String[] args) {
        Class fc = Farther.class;
        Child ch = new Child();
        Farther fa = new Farther();
        print(fc == ch.getClass());
        print(fc == fa.getClass());
        print(fc.equals(ch.getClass()));
        print(fc.equals(fa.getClass()));
    }
}
/*
loading farther
loading child
false
true
false
true
*/

與instanceof的區別在於直接比較沒有考慮繼承,而且使用了泛型語法時可能不能用 == 來比較。

相關文章
相關標籤/搜索