反射

反射機制

反射是一種機制,利用該機制可以在程序運行過程中,對類進行解剖,並獲得操作類中的方法,屬性,構造成員等。
反射就直接操作class字節碼,獲得方法,屬性,構造成員。

反射是在生成字節碼文件之後,對字節碼文件進行的操作。

1、獲取Class對象的三種方式

//創建測試類試Student
public class Student{
    //屬性
    //行爲
}

方式1、通過類名.class獲取

//格式:類名.class 屬性
//常用場景:反射獲取方式,確定方法的形參列表類型
public void test01(){
    Class<Student> cls = Student.class;   
}

方式2、通過Object類的成員方法getClass()方法獲取

public void test02(){
    Student stu = new Student();
    showInfo(stu);
}
public void showInfo(Object obj){
    // 方式二 : 使用對象名調用 getClass() 方法.
    // 格式 : 對象名.getClass() 方法.
    // 使用場景 : 在方法內部, 確定傳入形參的真實類型
    Class<?> cls = obj.getClass();
    System.out.println("cls="+cls)
}

方式3、通過Class.forName(“全限定類名”)方法獲取

public void test3() throws ClassNotFoundException {

        // 方式三 : 使用 Class 調用靜態方法 forName(全限定類名);   `包名+類名`
        // 使用場景 : 加載外部的配置文件時使用

        Class<?> cls = Class.forName("cn.itcast.test2.Student");
        System.out.println("cls = " + cls);
    }

在獲取類對象之後,介紹幾個Class類中的常用方法

獲取Class中Constructor的相關方法

1.Constructor getConstructor(Class...parameterType);
//根據參數類型獲取構造方法對象,只能獲得public修飾的構造方法。
//如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。

2.Constructor getDeclaredConstructor(Class...parameter);
//根據參數類型獲取構造方法對象,包括private修飾的構造方法。
//如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。

3. Constructor[] getConstructors() ;
//獲取所有的public修飾的構造方法

4. Constructor[] getDeclaredConstructors(); 
//獲取所有構造方法,包括privat修飾的

Constructor類中的常用方法

1. T newInstance(Object... initargs) 
    //根據指定參數創建對象。
2. void setAccessible(true)
    //暴力反射,設置爲可以直接訪問私有類型的構造方法。

示例

學生類
public class Student {
    // 屬性
    private String name;
    private int age;
    private char gender;

    // 公開構造方法 :
    public Student(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    // 私有構造方法 :
    private Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 公開無參構造方法
    public Student() {
    }

    // 行爲

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender=" + gender +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }
}

示例方法1


 public void testConstructor1() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 getConstructor 方法
        Constructor<?> constructor = cls.getConstructor(String.class, int.class, char.class);

        // 3. 調用 Constructor 對象的 newInstance 方法, 創建對象
        Object obj = constructor.newInstance("柳巖", 18, '女');

        // 4. 查看創建的對象
        System.out.println("obj = " + obj);
    }
   ```
#### 示例方法2
   ```

        public void testDeclaredConstructor2() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 getDeclaredConstructor 方法
        Constructor<?> constructor = cls.getDeclaredConstructor(String.class, int.class);

        // 3. 暴力反射 (設置可訪問權限)
        constructor.setAccessible(true);

        // 4. 調用 Constructor 對象的 newInstance 方法, 創建對象
        Object obj = constructor.newInstance("柳巖", 18);

        // 5. 查看創建的對象
        System.out.println("obj = " + obj);
    }

Class類中與Method相關方法

1. Method getMethod("方法名", 方法的參數類型... 類型)  ;
//根據方法名和參數類型獲得一個方法對象,只能是獲取public修飾的

2. Method getDeclaredMethod("方法名", 方法的參數類型... 類型);
//根據方法名和參數類型獲得一個方法對象,包括private修飾的

3. Method[] getMethods() (瞭解);
//獲取所有的public修飾的成員方法,包括父類中。

4. Method[] getDeclaredMethods() (瞭解);
//獲取當前類中所有的方法,包含私有的,不包括父類中。

method類中的常用方法

1.  Object invoke(Object obj, Object... args) ;
    //根據參數args調用對象obj的該成員方法 
    //如果obj=null,則表示該方法是靜態方法

2.  void setAccessible(boolean flag) ;
    //暴力反射,設置爲可以直接調用私有修飾的成員方法

示例代碼1

    @Test
    public void testMethod1() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 getMethod 方法
        Method eat = cls.getMethod("eat", String.class);

        // 3. 調用 invoke 方法
        Object obj = cls.getDeclaredConstructor().newInstance();
        eat.invoke(obj, "牛肉");
    }

示例代碼2

    @Test
    public void testDeclaredMethod2() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 declaredMethod 方法
        Method sleep = cls.getDeclaredMethod("fallInLove");

        // 3. 暴力反射 (設置可訪問權限)
        sleep.setAccessible(true);

        // 4. 調用 invoke 執行
        Object obj = cls.getDeclaredConstructor().newInstance();
        sleep.invoke(obj);
    }

Class類中與Field相關方法

1. Field getDeclaredField(String name) ;
//   根據屬性名獲得屬性對象,包括private修飾的

2. Field getField(String name) ;
// 根據屬性名獲得屬性對象,只能獲取public修1飾的

3. Field[]  getFields() ;
//    獲取所有的public修飾的屬性對象,返回數組。

4. Field[]  getDeclaredFields() ;
//  獲取所有的屬性對象,包括private修飾的,返回數組。

Field類中常用方法

void set(Object obj, Object value) ;
Object get(Object obj)  ;

void setAccessible(true);
//暴力反射,設置爲可以直接訪問私有類型的屬性。
Class getType(); 
//獲取屬性的類型,返回Class對象

示例代碼1

    public void testField1() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 getField 方法
        Field description = cls.getField("description");

        // 3. 設置屬性
        Object obj = cls.getDeclaredConstructor().newInstance();
        description.set(obj, "這就是那個神奇的學生.");

        // 4. 獲取屬性
        Object desc = description.get(obj);
        System.out.println("desc = " + desc);
    }

輸出結果 :
desc = 這就是那個神奇的學生.

代碼示例2

    @Test
    public void testDeclaredField2() throws Exception {

        // 1. 獲取 Student 類表示的 Class 對象
        Class<?> cls = Class.forName("cn.itcast.test2.Student");

        // 2. 調用 getDeclaredField 方法
        Field name = cls.getDeclaredField("name");

        // 3. 暴力反射
        name.setAccessible(true);

        // 4. 設置屬性
        Object obj = cls.getDeclaredConstructor().newInstance();
        name.set(obj, "渣渣輝");

        // 5. 查看
        System.out.println(obj);
    }
輸出結果 :
Student{name='渣渣輝', age=0, gender= }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章