Java基礎——深入理解反射

it_was發表於2020-09-17

反射是框架的靈魂!但先要獲取到每一個位元組碼檔案對應的Class型別的物件.

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

  • 反射就是把Java類中的各種成分對映成一個個的Java物件,所以運用反射必須依賴於目標類是否被載入,即首先需要經行類載入,獲取該類在Java記憶體(方法區)中這個唯一例項才可

  • Class 類的例項表示正在執行的 Java 應用程式中的類和介面。也就是jvm中有N多的例項每個類都有該Class物件。(包括基本資料型別)

  • Class 沒有公共構造方法。Class 物件是在載入類時由 Java 虛擬機器以及透過呼叫類載入器中的defineClass 方法自動構造的。也就是這不需要我們自己去處理建立,JVM已經幫我們建立好了。

:boom:3.1 獲取Class物件的三種方式

:one: Object->getClass();

public class Main {
    public static void main(String[] args){
       Parent parent = new Parent();
        Class pclass = parent.getClass(); 
        //是因為Object類中的getClass方法、因為所有類都繼承Object類。從而呼叫Object類來獲取
    }
}
class Parent{
}

:two: 任何資料型別都有靜態class屬性

public class Main {
    public static void main(String[] args){
        Class pclass = Parent.class; 
        // 任何資料型別(包括基本資料型別)都有一個“靜態”的class屬性
    }
}
class Parent{
}

:three: Class.forName(String className)

public class Main {
    public static void main(String[] args){
        Class pclass = Class.forName("ddx.Main");
        //透過Class類的靜態方法:forName(String  className)(常用)
    }
}
class Parent{
}

:boom: 三種方式常用第三種,第一種物件都有了還要反射干什麼。第二種需要匯入類的包,依賴太強,不導包就拋編譯錯誤。一般都第三種,一個字串可以傳入也可寫在配置檔案中等多種方法。

2、透過反射獲取構造方法並使用:

package fanshe;

public class Student {

    //---------------構造方法-------------------
    //(預設的構造方法)
    Student(String str){
        System.out.println("(預設)的構造方法 s = " + str);
    }

    //無參構造方法
    public Student(){
        System.out.println("呼叫了公有、無參構造方法執行了。。。");
    }

    //有一個引數的構造方法
    public Student(char name){
        System.out.println("姓名:" + name);
    }

    //有多個引數的構造方法
    public Student(String name ,int age){
        System.out.println("姓名:"+name+"年齡:"+ age);//這的執行效率有問題,以後解決。
    }

    //受保護的構造方法
    protected Student(boolean n){
        System.out.println("受保護的構造方法 n = " + n);
    }

    //私有構造方法
    private Student(int age){
        System.out.println("私有的構造方法   年齡:"+ age);
    }

}

測試類:

package fanshe;

import java.lang.reflect.Constructor;


/*
 * 透過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員;
 * 
 * 1.獲取構造方法:
 *         1).批次的方法:
 *             public Constructor[] getConstructors():所有"公有的"構造方法
            public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)

 *         2).獲取單個的方法,並呼叫:
 *             public Constructor getConstructor(Class... parameterTypes):獲取單個的"公有的"構造方法:
 *             public Constructor getDeclaredConstructor(Class... parameterTypes):獲取"某個構造方法"可以是私有的,或受保護、預設、公有;
 *         
 *             呼叫構造方法:
 *             Constructor-->newInstance(Object... initargs)
 */
public class Constructors {

    public static void main(String[] args) throws Exception {
        //1.載入Class物件
        Class clazz = Class.forName("fanshe.Student");


        //2.獲取所有公有構造方法
        System.out.println("**********************所有公有構造方法*********************************");
        Constructor[] conArray = clazz.getConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }


        System.out.println("************所有的構造方法(包括:私有、受保護、預設、公有)***************");
        conArray = clazz.getDeclaredConstructors();
        for(Constructor c : conArray){
            System.out.println(c);
        }

        System.out.println("*****************獲取公有、無參的構造方法*******************************");
        Constructor con = clazz.getConstructor(null);
        //1>、因為是無參的構造方法所以型別是一個null,不寫也可以:這裡需要的是一個引數的型別,切記是型別
        //2>、返回的是描述這個無參建構函式的類物件。

        System.out.println("con = " + con);
        //呼叫構造方法
        Object obj = con.newInstance();
    //    System.out.println("obj = " + obj);
    //    Student stu = (Student)obj;

        System.out.println("******************獲取私有構造方法,並呼叫*******************************");
        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);
        //呼叫構造方法
        con.setAccessible(true);//暴力訪問(忽略掉訪問修飾符)
        obj = con.newInstance('男');
    }

}

4.獲取成員變數並呼叫


package fanshe.field;
import java.lang.reflect.Field;
/*
 * 獲取成員變數並呼叫:
 * 
 * 1.批次的
 *         1).Field[] getFields():獲取所有的"公有欄位"
 *         2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
 * 2.獲取單個的:
 *         1).public Field getField(String fieldName):獲取某個"公有的"欄位;
 *         2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
 * 
 *      設定欄位的值:
 *         Field --> public void set(Object obj,Object value):
 *                     引數說明:
 *                     1.obj:要設定的欄位所在的物件;
 *                     2.value:要為欄位設定的值;
 * 
 */
public class Fields {

        public static void main(String[] args) throws Exception {
            //1.獲取Class物件
            Class stuClass = Class.forName("fanshe.field.Student");
            //2.獲取欄位
            System.out.println("************獲取所有公有的欄位********************");
            Field[] fieldArray = stuClass.getFields();
            for(Field f : fieldArray){
                System.out.println(f);
            }
            System.out.println("************獲取所有的欄位(包括私有、受保護、預設的)********************");
            fieldArray = stuClass.getDeclaredFields();
            for(Field f : fieldArray){
                System.out.println(f);
            }
            System.out.println("*************獲取公有欄位**並呼叫***********************************");
            Field f = stuClass.getField("name");
            System.out.println(f);
            //獲取一個物件
            Object obj = stuClass.getConstructor().newInstance();//產生Student物件--》Student stu = new Student();
            //為欄位設定值
            f.set(obj, "劉德華");//為Student物件中的name屬性賦值--》stu.name = "劉德華"
            //驗證
            Student stu = (Student)obj;
            System.out.println("驗證姓名:" + stu.name);


            System.out.println("**************獲取私有欄位****並呼叫********************************");
            f = stuClass.getDeclaredField("phoneNum");
            System.out.println(f);
            f.setAccessible(true);//暴力反射,解除私有限定
            f.set(obj, "18888889999");
            System.out.println("驗證電話:" + stu);

        }
    }

4、獲取成員方法並呼叫

5、反射main方法

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章