Java中有兩種方式讓咱們在運行時識別對象的類的信息:傳統的RTTI(Run-Time Type Identification)和反射。數組
Class對象包含了與類有關的信息,用來建立類的全部「常規」對象的特殊對象。每個類都有一個Class對象。dom
能夠用兩種方式來建立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 */
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 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返回一個布爾值,告訴咱們是否是某個特定類型的實例。
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。
也可使用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對象:
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的區別在於直接比較沒有考慮繼承,而且使用了泛型語法時可能不能用 == 來比較。