反射的概念 和基本使用(一)

1 反射

什麼是反射

java反射 是指在運行狀態中 對於任意一個類 我們都可以知到這個類的所有方法和屬性 也可以調用其所有的方法和屬性 這種動態獲取的方式 我們稱為 反射

什麼是class對象

我們通過使用反射 就是通過Class類來實現的 Class 類的實例表示正在運行的 Java 應用程式中的類和介面。

也就是jvm中有N多的實例每個類都有該Class對象。(包括基本數據類型)

反射的使用

獲取class對象的三種方式

基本類
/**
 *
 * @author : look-word
 * @date : 2022-04-05 20:49
 **/
public class Student {
    private String username;
    private String gender;

    public  String getInfo() {
        this.setUsername("張三");
        this.setGender("男");
        return this.username+"="+this.gender;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}
測試程式碼如下
/**
 * @author : look-word
 * @date : 2022-04-05 20:54
 **/
public class Test {
    public static void main(String[] args) {

        /*
            1 創建對象 獲取其class對象
         */
        Student student = new Student();
        Class<? extends Student> aClass = student.getClass();
        System.out.println(aClass.getSimpleName());
        /*
            2 任何數據類型(包括基本數據類型)都有一個「靜態」的class屬性
         */
        Class<? extends Student> bClass=Student.class;
        System.out.println(aClass == bClass?"兩者是同一對象":"兩者不是同一對象");
        /*
            3 通過Class類的forName方法獲取
         */
        try {
            //  Class.forName(類的相對路徑)
            Class<?> cClass = Class.forName("bean.Student");
            System.out.println(bClass == cClass?"兩者是同一對象":"兩者不是同一對象");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
結果如下

證明

在運行期間 一個類只有一個class對象的產生

常用的是第三次 清晰 明了 因為 在一個項目中 可能會產生 相同名字的類

解決疑惑 為什麼要是用 第三種

第一種對象都有了還要反射幹什麼。

第二種需要導入類的包,依賴太強,不導包就拋編譯錯誤。

第三種,一個字元串可以傳入也可寫在配置文件中等多種方法。

獲取Class類中的所有構造方法

基本類
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);
    }
}
測試程式碼
/**
 * 測試構造方法
 * @author : look-word
 * @date : 2022-04-05 21:18
 **/
public class TestConstructor {

/**
 * 通過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 static void main(String[] args) throws Exception {
        Class<?> student = Class.forName("bean.Student");
        /*
            1 獲取所有共有的構造方法
         */
        System.out.println("\n1 獲取所有共有的構造方法");
        Constructor<?>[] constructors = student.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        /*
            2 獲取共有的無參構造方法 可以寫 null 或者 不填
         */
        System.out.println("\n2 獲取共有的無參構造方法 可以寫 null 或者 不填");
        Constructor<?> constructor2 = student.getConstructor();
        constructor2.newInstance();

        /*
            3 獲取 給定參數共有的構造方法 public bean.Student(java.lang.String,int)
         */
        System.out.println("\n 3 獲取 給定參數共有的構造方法 public bean.Student(java.lang.String,int)");
        Constructor<?> constructor3 = student.getConstructor(String.class, int.class);
        constructor3.newInstance("張三",19);

        /*
            4 獲取 私有給定參數的構造方法 私有 不給定參數 不傳參數即可
         */
        Constructor<?> constructor4 = student.getDeclaredConstructor(int.class);
        /*
            獲取私有的屬性 或者構造方法是 需要 設置無障礙 俗稱 暴力訪問
            不設置 會出異常 java.lang.IllegalAccessException
         */
        constructor4.setAccessible(true);
        constructor4.newInstance(19);
    }
}

執行結果

注意

獲取私有屬性的時候 一定要設置無障礙

setAccessible(true);

不設置 會出異常 java.lang.IllegalAccessException

newInstance(Object… initargs) 創建一個新實例
使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。

每次是用 newInstance創建的對象 都是不同的對象 代表不同的實例

操作成員變數

基本類
 
public class Student {
	public Student(){
		
	}
	//**********欄位*************//
	public String name;
	protected int age;
	char sex;
	private String phoneNum;
	
	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", sex=" + sex
				+ ", phoneNum=" + phoneNum + "]";
	}
}
測試程式碼
/**
 * @author : look-word
 * @date : 2022-04-05 21:55
 **/
public class TestField {

/*
 * 獲取成員變數並調用:
 *
 * 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 static void main(String[] args) throws Exception{
        Class<?> aClass = Class.forName("bean.Student");
        Student student = new Student();

        /*
            獲取所有的共有欄位
         */
        System.out.println("-------------------獲取所有的共有欄位--------------------");
        Field[] fields = aClass.getFields();
        for (Field field : fields) {
            /*
                filed => public java.lang.String bean.Student.username
                filed => 成員變數
             */

            /*
               我理解為 給某個對象的 成員變數 賦值
               當前的filed 為 username 因為這裡只能獲取為 共有屬性的成員變數
             * field.set(student,"zhangsan");
             */
            field.set(student,"zhangsan");
            System.out.println(student);
            /*
                field.get(student);
                獲取某student中的 field 的 內容
             */
            Object o = field.get(student);
            System.out.println(o);
            /*
             *  列印filed的內容 => public java.lang.String bean.Student.username
             */
            System.out.println(field);
        }

        System.out.println("-------------------給私有欄位賦值--------------------");
        Field phone = aClass.getDeclaredField("phone");
        phone.setAccessible(true);// 設置無障礙 
        phone.set(student,"110");// 賦值給student對象

        System.out.println("-------------------獲取私有欄位--------------------");
        Field phone1 = aClass.getDeclaredField("phone");
        phone1.setAccessible(true);// 設置無障礙
        System.out.println(phone1.get(student));//取出student對象中的phone屬性的值
    }
}
注意

在操作私有屬性的時候 不管是獲取還是設置值 都需要設置無障礙

setAccessible(true);// 設置無障礙

Tags: