反射概述
* JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;
* 對於任意一個對象,都能夠調用它的任意一個方法和屬性;
* 這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
* 要想解剖一個類,必須先要獲取到該類的字節碼文件對象。
* 而解剖使用的就是Class類中的方法,所以先要獲取到每一個字節碼文件對應的Class類型的對象。
反射的三種方式
* a:通過Object類的getClass()來獲取
java.lang.Object中定義有getClass方法:public final Class getClass()所有Java對象都具備這個方法,該方法用於返回調用該方法的對象的所屬類關聯的Class對象,例如:
Date date1 = new Date();
Date date2 = new Date();
Class c1 = date1.getClass();
Class c2 = date2.getClass();
System.out.println(c1.getName());
// java.util.Date
System.out.println(c1 == c2);
// true
上面的代碼中,調用Date對象date1的getClass方法將返回用於封裝Date類信息的Class對象。這裏調用了Class類的getName方法:public String getName(),這個方法的含義很直觀,即返回所封裝的類的名稱。需要注意的是,代碼中的date1和date2的getClass方法返回了相同的Class對象(c1==c2的值爲true)。這是因爲,對於相同的類,JVM只會載入一次,而與該類對應的Class對象也只會存在一個,無論該類實例化了多少對象。另外,需要強調的是,當一個對象被其父類的引用或其實現的接口類型的引用所指向時,getClass方法返回的是與對象實際所屬類關聯的Class對象。例如:
List list = new ArrayList(); System.out.println(list.getClass().getName()); // java.util.ArrayList
上面的代碼中,語句list.getClass()方法返回的是list所指向對象實際所屬類java.util.ArrayList對應的 Class對象而並未java.util.List所對應的Class對象。有些時候可以通過這個方法瞭解一個對象的運行時類型,例如:
HashSet set = new HashSet();
Iterator it = set.iterator(); System.out.println(it.getClass().getName());
//java.util.HashMap$KeyIterator
從代碼可以看出,HashSet的iterator方法返回的是實現了Iterator接口的HashMap內部類(KeyIterator)對象。因爲抽象類和接口不可能實例化對象,因此不能通過Object的getClass方法獲得與抽象類和接口關聯的Class對象。
* b:使用.class的方式
使用類名加“.class”的方式即會返回與該類對應的Class對象。Class clazz = String.class;
System.out.println(clazz.getName());
// java.lang.String
這個方法可以直接獲得與指定類關聯的Class對象,而並不需要有該類的對象存在。
* c:使用Class.forName()的方法
Class有一個著名的static方法forName:public static Class forName(String className) throws ClassNotFoundException該方法可以根據字符串參數所指定的類名獲取與該類關聯的Class對象。如果該類還沒有被裝入,該方法會將該類裝入JVM。該方法聲明拋出ClassNotFoundException異常。顧名思義,當該方法無法獲取需要裝入的類時(例如,在當前類路徑中不存在這個類),就會拋出這個異常。例如,如果當前類路徑中存在Foo類:
package org.whatisjava.reflect;
public class Foo {
public Foo() { System.out.println("Foo()"); }
static { System.out.println("Foo is initialized"); }
}
運行下面的代碼:
Class clazz=Class.forName("org.whatisjava.reflect.Foo");
控制檯會有如下輸出:
Foo is initialized Class.forName("org.whatisjava.reflect.Foo")
首先會將reflection.Foo類裝入JVM,並返回與之關聯的Class對象。JVM裝入Foo類後對其進行初始化,調用了其static塊中的代碼。需要注意的是:forName方法的參數是類的完 整限定名(即包含包名)。 區別於前面兩種獲取Class對象的方法:使用Class.forName方法所要獲取的與之對應的Class對象的類可以通過字符串的方式給定。該方法通常用於在程序運行時根據類名動態的載入該類並獲得與之對應的Class對象。