1. 程式人生 > >反射機制與Class類

反射機制與Class類

  從這節課開始, 我們正式進入java 反射機制的學習

 

  首先,什麼是java的反射機制?來看百度百科:

重點:

  1. 在執行狀態中
  2. 對任意一個實體類
  3. 對任意一個物件
  4. 動態獲取資訊
  5. 動態呼叫物件方法

 

  Java有個包,叫java.lang.reflect,這個包下的所有類都是為反射機制服務的,除此之外還有一個非常重要的類:java.lang.Class

 

public final class Class<T> implements java.io.Serializable
,                               GenericDeclaration,                              
Type,                               AnnotatedElement {

 

Class類:

  1. 反射機制的核心類,這個類包含了我們定義的類的所有屬性和方法以及類名
  2. 這個類的構造器是私有的,所以不用想著new了
  3. 獲取Class物件的方法有 類.class,物件.getClass(), Class.forName(String className)              等

 

接下來來看看程式碼:

package reflection;



import helloworld.MyArrayList;



import java.lang.reflect.Field;



public class ClassTeach {



    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {

        /**

         * Class類可以動態獲取任意實體類的屬性和方法,那麼,我們隨便挑個類來試試

         * 比如之前我們自己寫過的MyArrayList

         */

        //第一種獲取Class物件的方法: 類.class

        Class clazz1 = MyArrayList.class;



        //第二種獲取Class物件的方法: 物件.getClass()

        MyArrayList<Object> list = new MyArrayList<>();

        Class clazz2 = list.getClass();



        //第三種獲取Class物件的方法: Class.forName() 引數是全類名,即完整包名+類名

        //這個方法可能會丟擲ClassNotFoundException,表示要載入的類找不到,這個異常是編譯時異常

        Class clazz3 = Class.forName("helloworld.MyArrayList");



        /**

         * 根據百科裡的內容,反射機制是可以動態獲取一個類的所有屬性和方法的

         * 我們來試試

         * 首先,查API文件,看看有什麼方法可以獲取屬性和方法

         *

         * public Field getDeclaredField(String name)

         * 返回一個Field物件,它反映此表示的類或介面的指定已宣告欄位類物件。 name引數是一個String ,它指定了所需欄位的簡單名稱。

         *

         * OK,這裡又牽扯出一個新的類 Field,大家可以暫停視訊猜猜在哪個包下

         * 揭曉答案, 在java.lang.reflect下,看英語我肯定看得懂,怕你們看不懂,還是來看API文件

         *

         * Filed 提供有關類或介面的單個欄位的資訊和動態訪問。 反射的欄位可以是類(靜態)欄位或例項欄位。

         * 所謂欄位,其實就是屬性

         */

        //用clazz1來試試獲取屬性

        //MyArrayList裡有一個size屬性,來獲取的看看

        //此方法可能報一個異常NoSuchFieldException,表示沒有這樣的一個屬性

        Field sizeField = clazz1.getDeclaredField("size");

        System.out.println(sizeField.getName());    //size

        /**

         * 來介紹下Field比較常用的三個方法

         * getName()  獲取屬性名稱

         * set(Object obj, Object value) 給obj的Field對應的屬性賦值value

         * get(Object obj) 獲取obj的Field對應的屬性的值

         */

        //前面我們new了一個list物件,現在來試試

        //set方法會報一個異常IllegalAccessException,表示非法接觸異常,即如果物件是private的你是不能直接接觸的

        //剛說完可能報異常立馬報了,因為size屬性是私有的

        //如果我們非要給size屬性賦值怎麼辦?

        //設定accessible為true即可

        sizeField.setAccessible(true);

        sizeField.set(list,2);

        //不報錯了

        //現在來看看list的size屬性的值

        System.out.println(list.size());    //可以看到已經給list的size屬性賦值了

        //再來用引用獲取的看看

        //get方法依然會拋異常,而且還是兩個 IllegalArgumentException, IllegalAccessException

        //一個非法引數,一個非法接觸

        System.out.println(sizeField.get(list));

        //可以看到通過get也可以動態獲取



        //最後來輸出下Class對應的類的名字吧,下節課再來講動態獲取方法

        System.out.println(clazz1.getName());   //helloworld.MyArrayList





    }

}