Java提供的反射機制允許我們在運行時期動態加載類,檢測和修改它本身狀態或行爲,要舉反射機制的一個實例的話,就是在整合開發環境中所提供的方法提示或者類的檢查工具,另外像jsp中的javabean自動收集請求也用到了反射,還有我們經常用的框架也可以看到反射機制的使用,這樣可以達到動態加載使用者自己定義的類的目的。
在我們拿到一個類時,即使對它一無所知,但是其實他本身就包括了很多信息,Java在需要使用某個類時纔會將類加載,並在jvm中以一個java.lang.Class的實例存在,從Class實例開始,我們可以獲取類的信息。
Class類的加載
Java在真正需要使用一個類的時候纔會進行加載,而不是在程序啓動時加載所有的類,因爲大多數人都只使用到應用程序的部分資源,在需要某些功能時在加載某些資源,這樣可以讓系統的資源運用更有效率。
一個java.lang.Class代表了Java程序中運行時加載類或者接口的實例,也可以用來表達enum(枚舉),annotation(註解),數組,基本數據類型;Class類沒有public構造方法,Class是由jvm自動生成的,每當一個類被加載時,jvm就會自動生成一個Class實例。
我們還可以通過Object的getClass()方法來取得每一個對象對應Class實例,或者通過”class”常量,在取得Class實例之後,操作Class實例上的一些方法來取得類的基本信息,例如:
package CoreJava.day_2;
/**
* @author 李智
* @date 2016/12/3
*/
public class ClassDemo {
public static void main(String[] args) {
String name = "justdoitlee";
Class stringClass = name.getClass();
System.out.println("類名稱:" +
stringClass.getName());
System.out.println("是否爲接口:" +
stringClass.isInterface());
System.out.println("是否爲基本數據類型:" +
stringClass.isPrimitive());
System.out.println("是否爲數組:" +
stringClass.isArray());
System.out.println("父類名稱:" +
stringClass.getSuperclass().getName());
}
}
執行結果:
類名稱:java.lang.String
是否爲藉口:false
是否爲基本數據類型:false
是否爲數組:false
父類名稱:java.lang.Object
Process finished with exit code 0
這裏簡單的的使用 getClass() 方法來取得 String 類的 Class 實例,並從中得到 String 的一些基本信息。
當然,我們也可以直接使用下面的方式來取得String類的Class對象:
Class stringClass = String.class;
Java在真正需要類時纔會加載這個類,所謂的真正需要通常指的是要使用指定的類生成對象時,或者使用指定要加載的類時,例如使用Class.forName()加載類,或者使用ClassLoader的loadClass()加載類,聲明類並不會導致類的加載,可以使用一個小測試來驗證。
package CoreJava.day_2;
/**
* @author 李智
* @date 2016/12/3
*/
public class TestClass {
static {
System.out.println("類被加載");
}
}
在上面我們定義了一個靜態代碼塊,假設在類第一次被加載時會執行靜態代碼塊(說假設是因爲,可以設置加載類時不執行靜態代碼塊,使Class生成對象時才執行靜態代碼塊),看輸出信息可以看出類何時被加載(如下LoadClassTest)。
package CoreJava.day_2;
/**
* @author 李智
* @date 2016/12/3
*/
public class LoadClassTest {
public static void main(String[] args) {
TestClass test = null;
System.out.println("聲明TestClass");
test = new TestClass();
System.out.println("生成TestClass實例");
}
}
輸出:
聲明TestClass
類被加載
生成TestClass實例
Process finished with exit code 0
從執行結果可以看出,聲明類並不會導致TestClass被加載,而是在使用new生成對象時纔會被加載類。
Class的信息是在編譯時期就被加入至.class文件的,這是Java執行時期被辨別(RTTI,Run-Time Type Information或Run-Time Type Identification)的一種方式,在編譯時期編譯器會先檢查對應的.class文件,而執行時期jvm在使用類時,會先檢查對應的Class是否已經被加載,如果沒有加載,則會尋找對應的,class文件並加載,一個類在jvm中只會有一個Class實例,每個類的實例都會記得自己是由哪個Class實例所生成,我們可以使用getClass()或.class來取得Class實例。
另外,在Java中,數組對象也有對應的Class實例,這個對象是由具有相同元素與維度的數組所共用,而基本類型像是 boolean, byte, char, short, int, long, float, double 以及關鍵字 void(以前都不知道有這個呢!!),也都具有對應的Class對象,我們還可以用類常量(Class literal)來獲取這些對象。
package CoreJava.day_2;
/**
* @author 李智
* @date 2016/12/4
*/
public class ClassDemo2 {
public static void main(String[] args) {
System.out.println(boolean.class);
System.out.println(void.class);
int[] iarr = new int[10];
System.out.println(iarr.getClass().toString());
double[] darr = new double[10];
System.out.println(darr.getClass().toString());
}
}
輸出:
boolean
void
class [I
class [D
Process finished with exit code 0
在Java中 數組確實是以對象的形式存在的,其對應的類都是有jvm自動生成的,當我們是用toString()來顯示數組對象的描述時,[表示爲數組類型,並且加上一個類型代表字,上面的I表示是一個Int的數組,d是一個double數組。
這裏就先講一下Class類的加載吧,後面的再總結。