Java反射學習總結(一)

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類的加載吧,後面的再總結。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章