java反射之Class類

weixin_33866037發表於2018-04-29

上節我們對反射有了初步的瞭解,我們知道,反射就是在執行期間動態的來獲取一個類的屬性(構造器、方法、欄位、介面)等,這節我們來看看反射的基礎Class類。

什麼叫Class類

 > 1.顧明思議,我們通過API可以瞭解到,class類就是用來描述類或介面的型別,簡單說就是描述類的一種類。

什麼叫Class例項

 > 表示正在執行的 Java 應用程式中的類和介面,這是官方的解釋。
   我自己認為就是在JVM裡的一份位元組碼檔案。
   即存在於JVM裡的類或者介面,其中列舉是一種類,註釋是一種介面,比如
   java.util.Date這個類來說,當程式第一次建立這個類時,就會把該類的位元組碼檔案
   裝載到JVM裡,此時的Class就是java.util.Date的位元組碼。

那麼我們從上面這個小小的例子中能知道什麼,不難發現,既然Class類能代表java.util.Date的位元組碼,是不是我們也可以認為Class類也可以代表String類的位元組碼檔案呢?,依次類推,那所有的物件的位元組碼檔案是否Class類都能表示了,答案是肯定的,問題來了,這麼多類,如何來區分它到底代表那個類的位元組碼檔案呢?我們通過API可以發現,Class設計者為它提供了泛型------>Class<T>幫我們解決了這個困擾,如:
java.lang.String類的位元組碼檔案:Class<java.lang.String>;
java.util.ArrayList類的位元組碼檔案:Class<java.util.ArrayList>等,接下來我們來看看如何建立Class物件。

Class物件的建立

> 1.通過class屬性,類名.class
    需求:獲取java.util.Date物件的class位元組碼
    Class<java.util.Date> clazz1 = java.util.Date.class;
方式二
     >2.通過物件的getClass屬性來獲取
       Date date = new Date();
       Class<? extends Date> clazz2 = date.getClass();
方式三
     >3.通過class類中的靜態方法forName(String name)來獲取
       Class<?> clazz3 = Class.forName("java.util.Date");

以上就是Class類的三種建立過程,下面我們來看完整的程式碼示例以及三種方式的對比。

程式碼示例如下:
public static void main(String[] args)throws Exception {

    //需求:獲取java.util.Date物件的class類
    //方式1.class 屬性
    Class<java.util.Date> clazz1 = java.util.Date.class;
    //方式2通過物件的getClass屬性來獲取,
    Date date = new Date();
    Class<? extends Date> clazz2 = date.getClass();
    //方式三通過class類中的靜態方法forName(String name)來獲取
    Class<?> clazz3 = Class.forName("java.util.Date");
    System.out.println(clazz1);
    System.out.println(clazz2);
    System.out.println(clazz3);

    System.out.println(clazz1 == clazz2);
    System.out.println(clazz1 == clazz3);
    System.out.println(clazz2 == clazz3);
}
執行結果如下:
 ![image.png](https://upload-images.jianshu.io/upload_images/3711017-dc7ab00729bc4ac1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

通過結果我們可以發現,三種方式建立的位元組碼檔案一樣,說明了一個問題,同一個類的位元組碼檔案在JVM只存在一份。知道了如何建立Class類的方式,我們如何來表示基本資料型別的Class物件了,最起碼的我們不能用getClass的方式,也不能用Class.forName的方式,因為基本型別沒有類名這個概念,如何表示基本型別的位元組碼物件了?
我們通過Class的API可以找到,所有的資料型別都有class屬性,那麼問題就簡單了,也就是說基本型別的位元組碼物件可以這樣表示:
Class clazz = 資料型別.class;

九大內建class類的例項:
     > 在我們程式執行前,JVM預先提供了class的例項,如:
     byte、char、short、int、long、float、double、boolean和void。那麼它們的位元組碼物件如何表示了我們看程式碼:
程式碼如下:
public static void main(String[] args) {

    //基本資料型別位元組碼物件

    Class intClass = int.class;
    Class byteClass = byte.class;
    Class shortClass = short.class;
    Class charClass = char.class;
    Class longClass = long.class;
    Class floatClass = float.class;
    Class doubleClass = double.class;
    Class booleanClass = boolean.class;
    Class voidClass = void.class;
    //列印結果
    System.out.println(intClass);
    System.out.println(byteClass);
    System.out.println(shortClass);
    System.out.println(charClass);
    System.out.println(longClass);
    System.out.println(floatClass);
    System.out.println(doubleClass);
    System.out.println(booleanClass);
    System.out.println(voidClass);
結果如下:
3711017-b80ee78b10c6bf83.png
image.png

上圖是我們執行後的結果,我們拿到了基本型別的位元組碼。在8大基本型別的包裝類中,都有一個常量TYPE,它表示返回該包裝類所對應的基本型別的位元組碼物件,如圖:


3711017-7218047fc5184f1e.png
imag2.png
程式碼示例如下:
     Class intClass = int.class;
     Class<Integer> type = Integer.TYPE;
     System.out.println(intClass == type);

我只是寫了int型別的,其他的都一樣,我們看測試結果:


3711017-7ffc4ccae95789cc.png
QQ截圖20180430150227.png

注意:Integer和int是不同的型別,不能認為Integer.class 和int.class 的位元組碼物件相等。

陣列的class例項:
     > 我們知道陣列是引用型別,也就是說陣列也是物件,我們來看如何表示陣列的位元組碼物件?
      方式一:陣列型別.class;
      方式二:陣列物件.getClass();
程式碼如下:
  陣列的class例項
    方式一:陣列型別.class
    Class<int[]> clazz = int[].class;
    System.out.println(clazz);
    System.out.println("===========================");
    方式二:陣列物件.getClass()
    int [] arr = {1,2,3};
    Class<? extends int[]> arrClass = arr.getClass();
    System.out.println(arrClass);
結果如下:
3711017-b0a195f279ad461b.png
QQ截圖20180430152557.png

由上圖結果所示,我們通過不同的方式卻拿到了相同的位元組碼物件,總之,相同型別的位元組碼物件在JVM僅有一份,以上就是關於Class類的簡單講解,望廣大老鐵致電!!!!!

相關文章