1. 程式人生 > 實用技巧 >Java的反射機制

Java的反射機制

一、Java的反射概述

JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;

這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件。而解剖使用的就是Class類中的方法,所以先要獲取到每一個位元組碼檔案對應的Class型別的物件


新建Class類進行測試:

package com.hansun.entity;

public class Person {
    public String name;
    public int
age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String show(){ return "name:"+name+", age :"+age; } }

package com.hansun.entity;

public class Student extends Person {

    public String className;

    
private String address; public Student() { super(); } private Student(String name, int age, String className) { super(name, age); this.className = className; } public Student(String name, int age, String className, String address) { super(name, age);
this.className = className; this.address = address; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } private void add(int a, int b) { System.out.println(a + b); } @Override public String toString() { return "Student{" + "className='" + className + '\'' + ", address='" + address + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; } }

二、獲取反射的方式

// 通過Class類中的靜態方法forName,直接獲取到一個類的位元組碼檔案物件,此時該類還是原始檔階段,並沒有變為位元組碼檔案。
1、Class clazz1 = Class.forName("全限定類名");

//當類被載入成.class檔案時,此時Person類變成了.class,在獲取該位元組碼檔案物件,也就是獲取自己, 該類處於位元組碼階段。
2、Class clazz2  = Person.class;

//通過類的例項獲取該類的位元組碼檔案物件,該類處於建立物件階段
3、Class clazz3 = p.getClass();


驗證三種方式獲取的Class物件是否同一個

/**
 * 測試三種反射得來的Class物件  是否是同一個
 */
private static void testClass() throws ClassNotFoundException {
    // 第一種方式獲取Class物件
    // new 產生一個Student物件,一個Class物件。
    Student stu1 = new Student();
    //獲取Class物件
    Class stuClass = stu1.getClass();
    System.out.println(stuClass.getName());

    // 第二種方式獲取Class物件
    Class stuClass2 = Student.class;
    // 判斷第一種方式獲取的Class物件和第二種方式獲取的是否是同一個
    System.out.println(stuClass == stuClass2);

    // 第三種方式獲取Class物件
    // 注意此字串必須是真實路徑,就是帶包名的類路徑,包名.類名
    Class stuClass3 = Class.forName("com.hansun.entity.Student");
    // 判斷三種方式是否獲取的是同一個Class物件
    System.out.println(stuClass3 == stuClass2);

}

三、獲取類Class物件中成員變數Field欄位

private static void testField() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");
    //獲取成員變數,包括子類及父類,同時只能包含公共的方法
    Field[] fields = cls.getFields();
    for (Field field : fields) {
        System.out.print(field + "\t");
        System.out.print(field.getModifiers() + "\t");
        System.out.print(field.getType() + "\t");
        System.out.print(field.getName() + "\t");
        System.out.println();
    }
    System.out.println("========================");


    //此方法返回的是當前類的所有屬性,不僅僅侷限於公共訪問修飾符,所有的訪問修飾符都可以拿到
    Field[] declaredFields = cls.getDeclaredFields();
    for (Field declaredField : declaredFields) {
        System.out.print(declaredField + "\t");
        System.out.print(declaredField.getModifiers() + "\t");
        System.out.print(declaredField.getType() + "\t");
        System.out.println(declaredField.getName());
    }
    System.out.println("========================");


    // 反射在一定程度上破壞了封裝性,需要合理使用
    Field address = cls.getDeclaredField("address");
    // 設定該屬性是否能被訪問,true表示能被訪問,破壞了封裝性
    address.setAccessible(true);

    System.out.println(address.getName());
    Object o = cls.newInstance();
    address.set(o, "北京市");
    System.out.println(((Student) o).getAddress());
    System.out.println("========================");
}

四、獲取類Class物件中method方法

private static void testMethod() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");

    // 獲取該物件的普通方法,包含的方法範圍是當前物件及父類物件的所有公共方法
    Method[] methods = cls.getMethods();
    for (Method method : methods) {
        System.out.print(method.getModifiers() + "\t");
        System.out.print(method.getName() + "\t");
        System.out.println(Arrays.toString(method.getParameterTypes()));
    }
    System.out.println("-----------------------");


    // 獲取當前類中所有的方法,無論什麼訪問修飾符
    Method[] declaredMethods = cls.getDeclaredMethods();
    for (Method declaredMethod : declaredMethods) {
        System.out.print(declaredMethod.getModifiers() + "\t");
        System.out.print(declaredMethod.getName() + "\t");
        System.out.println(Arrays.toString(declaredMethod.getParameterTypes()));

    }
    System.out.println("-----------------------");


    Method add = cls.getDeclaredMethod("add", int.class, int.class);
    cls.getDeclaredMethods();
    add.setAccessible(true);
    Object o1 = cls.newInstance();
    add.invoke(o1, 123, 87);

    Method setAddress = cls.getDeclaredMethod("setAddress", String.class);
    setAddress.invoke(o1, "上海市!");
    System.out.println(o1.toString());
}

五、獲取類Class物件中的Constructor構造器

private static void testConstructor() throws Exception {
    Class cls = Class.forName("com.hansun.entity.Student");

    // 獲取物件的所有構造方法,只能獲取公有的改造方法
    Constructor[] constructors = cls.getConstructors();
    for (Constructor constructor : constructors) {
        System.out.print(constructor.getModifiers() + "\t");
        System.out.println(constructor.getName());
    }
    System.out.println("========================");
    // 獲取所有的構造方法,無論是私有還是公有
    Constructor[] declaredConstructors = cls.getDeclaredConstructors();
    for (Constructor declaredConstructor : declaredConstructors) {
        System.out.print(declaredConstructor.getModifiers() + "\t");
        System.out.print(declaredConstructor.getName() + "\t");
        // 獲取構造器中方法簽名
        System.out.print(Arrays.toString(declaredConstructor.getParameterTypes()) + "\t");
        System.out.println(declaredConstructor.getParameterCount() + "\t");
    }
    // 如何呼叫私有的構造方法呢?
    Constructor<Student> declaredConstructor = cls.getDeclaredConstructor(String.class, int.class, String.class);
    declaredConstructor.setAccessible(true);
    Student o2 = declaredConstructor.newInstance("sunhan", 23, "aaaaaaaaaaa");
    System.out.println(o2);
}