1. 程式人生 > >分享知識-快樂自己:反射機制Demo解析

分享知識-快樂自己:反射機制Demo解析

Java-Reflect專題

基本反射簡介:

1):JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。

2):JAVA反射(放射)機制:"程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言"。從這個觀看,Perl,PythonRuby是動態語言,C++,Java,C#不是動態語言。

3):但是JAVA有著一個非常突出的動態相關機制:Reflection用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。

4):換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。

Java反射機制提供的功能:

1):在執行時判斷任意一個物件所屬的類在執行時構造任意一個類的物件

2):在執行時判斷任意一個類所具有的成員變數和方法

3):在執行時呼叫任意一個物件的方法

4):生成動態代理

Class類介紹:

Class 類描述Java程式執行時的所有 Classes 和 interfaces,同時也用來描述enum、array、Java基本資料型別。

生成Class:當一個class檔案被載入或者類載入器的defineClass()被JVM呼叫時,JVM便自動產生一個Class 物件。

常用API:

生成Class物件的方法:

1):根據完整類名獲取類,呼叫 Class 的靜態方法 forName():

Class<?> classType = Class.forName(“java.lang.String”);

2):通過類名獲取,使用class語法,這裡ReflectionTest為一個類名:

Class<?> classType = ReflectionTest.class;

3):通過物件的getClass()方法獲取:

User user = new User();
Class<?> classType = user.getClass();
//獲取user的父類的Class物件
Class superClass = classType.getSuperclass();

4):對於包裝類的Class的獲取,使用包裝類的TYPE語法:

Class classType = Integer.Type;
Class c = Integer.class;

建立反射獲取的類的例項的方法:

1):呼叫Class的newInstance()方法:

Class c = Class.forName("mlq.Student");
Student student = (Student) c.newInstance();

2):通過Class獲取構造方法再例項化:

Class c = Class.forName("mlq.Student");
Student student=(Student)c.getConstructor(new Class[]{}).newInstance(new Object[]{});

提示:當Class陣列為空時,本質上等價於①,即呼叫無參建構函式

獲取方法資訊函式:

1):獲取所有公共方法:

Method getMethod(String name, Class[] params) -- 使用特定的引數型別,獲得命名的公共方法

Method[] getMethods() -- 獲得類的所有公共方法

2):獲取所有方法:(不問訪問許可權)

Method getDeclaredMethod(String name, Class[] params) -使用特寫的引數型別,獲得類宣告的命名的方法

Method[] getDeclaredMethods() -- 獲取的是所有該類自己宣告的方法,不問訪問許可權

獲取成員變數:

1):獲取所有的 public 的成員變數的資訊

Field getField(String name) -- 獲得指定命名的公共欄位

Field[]  getFields()--方法獲取的是所有的public的成員變數的資訊

2):獲取所有成員變數:(不問訪問許可權)

Field getDeclaredField(String name) -- 獲取指定的域,返回一個 Field 物件,該物件反映此 Class 物件所表示的類或介面的指定已宣告欄位:

Field[]  getDeclaredFields()--獲取所有的域,包括公共、保護、預設(包)訪問和私有域,但不包括繼承的域:

field.setAccessible(true);--設定壓制訪問控制檢查,這樣就可以獲取和設定私有域的值了:

Field field = classType.getDeclaredField("fieldName");--獲取某個物件的域的對應值:

field.get(object);

Field field = classType.getDeclaredField("fieldName");--設定某個物件的域的對應值:
field.set(obj, "arthinking");

獲取建構函式資訊:

1):獲取所有public的函式:

Constructor getConstructor(Class[] params) -- 獲得使用特殊的引數型別的公共建構函式,
Constructor[]  getConstructors()
--獲取所有的public的建構函式

2):獲取建構函式:(不問訪問許可權)

Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定引數型別的建構函式(與接入級別無關)
Constructor[]  getDeclaredConstructors()
--得到自己宣告的建構函式,推薦使用(與接入級別無關)

案例Demo:點我下載原始碼

1):獲取Student類的完整限定名==》全類名

/**
     * 獲取Student類的完整限定名==》全類名
     * 01、Class.forName(類的完整限定名) 來載入類 (常用)
     * 02、Student.class 任何類名.class都是獲取了Class類
     * 03、new Student().getClass() 任何物件.getClass()都是獲取了Class類
     */
    @Test
    public void test01() {
        try {

            System.out.println("列印類的完整限定名、會走靜態程式碼塊:" + Class.forName("mlq.Student"));
            System.out.println("====================================");
            System.out.println("只打印類的全名稱:" + Student.class);
            System.out.println("====================================");
            System.out.println("無參、靜態與非靜態塊、類完整名稱;都會執行" + new Student().getClass().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2):獲取包名、類名、訪問修飾符值 和 name

/**
     * 獲取包名、類名、訪問修飾符值 和 name
     */
    @Test
    public void test02() {
        try {
            //載入Student 類
            Class c = Class.forName("mlq.Student");
            System.out.println("Student所在包名稱:" + c.getPackage().getName());
            System.out.println("Student全類名:" + c.getName());
            System.out.println("Student類名:" + c.getSimpleName());
            //獲取類的訪問修飾符
            int num = c.getModifiers();
            System.out.println("public訪問修飾符對應的數值:" + num);
            //訪問修飾符對相應的名稱
            System.out.println(Modifier.toString(num));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

3): 獲取類中所有的屬性相關資訊

/**
     * 獲取類中所有的屬性相關資訊
     */
    @Test
    public void test03() {
        try {
            Class c = Class.forName("mlq.Student");
            //獲取所有欄位
            Field[] fields = c.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                System.out.println(fields[i]);
            }
            //獲取所有欄位的訪問修飾符
            for (int i = 0; i < fields.length; i++) {
                //修飾符值物件的修飾符名稱
                System.out.print(Modifier.toString(fields[i].getModifiers()));
                //訪問修飾符對應的數值
                System.out.println(":" + fields[i].getModifiers());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

4):獲取類中所有的方法相關資訊  不包含構造方法

/**
     * 獲取類中所有的方法相關資訊  不包含構造方法
     * 01、c.getMethod(方法名稱,引數型別)只能是public修飾的
     * 02、c.getMethods()只能是public修飾的
     * 03、c.getDeclaredMethods() 所有
     */
    @Test
    public void test04() {
        try {
            Class c = Class.forName("mlq.Student");
            //獲取所有方法,包含private私有的
            Method[] declaredMethods = c.getDeclaredMethods();
            for (int i = 0; i < declaredMethods.length; i++) {
                System.out.println("方法的名稱是:" + declaredMethods[i].getName());
                System.out.println("方法的修飾符數值時:" + declaredMethods[i].getModifiers());
                System.out.println("方法的修飾符名稱是:" + Modifier.toString(declaredMethods[i].getModifiers()));
                System.out.println("方法的返回值型別是:" + declaredMethods[i].getReturnType());
                System.out.println("=============================================");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

5):獲取類中的所有構造方法相關資訊

 /**
     * 獲取類中的所有構造方法相關資訊
     */
    @Test
    public void test05() {
        try {
            Class c = Class.forName("mlq.Student");
            //獲取所有構造,包含private私有的
            Constructor[] declaredConstructors = c.getDeclaredConstructors();
            for (int i = 0; i < declaredConstructors.length; i++) {
                System.out.println("構造方法的名稱是:" + declaredConstructors[i].getName());
                System.out.println("構造方法的修飾符數值是:" + declaredConstructors[i].getModifiers());
                System.out.print("構造的訪問修飾符及引數列表:" + Modifier.toString(declaredConstructors[i].getModifiers()) + "(");
                //獲取構造中的引數
                Class[] parameterTypes = declaredConstructors[i].getParameterTypes();
                for (int j = 0; j < parameterTypes.length; j++) {
                    System.out.print(parameterTypes[j].getName() + ",");
                }
                System.out.println(")");
                System.out.println("=======================================");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

6):訪問類中私有的屬性和方法並且讓它執行

/**
     * 訪問類中私有的屬性和方法並且讓它執行
     */
    @Test
    public void test06() {
        try {
            Class c = Class.forName("mlq.Student");
            //Student student=(Student)c.getConstructor(new Class[]{}).newInstance(new Object[]{});
            //例項化
            Student student = (Student) c.newInstance();
            //獲取私有欄位
            Field userName = c.getDeclaredField("userName");

            //輸出欄位名稱
            System.out.println("輸出欄位名稱:"+userName.getName());
            //開啟欄位開關
            userName.setAccessible(true);
            //userName.set(student,"abc");
            //輸出欄位資訊
            System.out.println("輸出欄位資訊:"+userName.get(student));
            //獲取私有的方法
            Method getSum = c.getDeclaredMethod("getSum", double.class);
            //開啟方法開關
            getSum.setAccessible(true);
            //呼叫執行方法
            double invoke = (Double) getSum.invoke(student, 50.5);
            //輸出返回值
            System.out.println(invoke);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

Face your past without regret. Handle your present with confidence.Prepare for future without fear. keep the faith and drop the fear.

面對過去無怨無悔,把握現在充滿信心,備戰未來無所畏懼。保持信念,克服恐懼!一點一滴的積累,一點一滴的沉澱,學技術需要不斷的積澱!