1. 程式人生 > 其它 >Java註解和反射04:獲取類的執行時結構

Java註解和反射04:獲取類的執行時結構

獲取執行時類的完整結構

通過反射可以獲得類實現的介面、父類、構造器、方法、屬性、註解

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {

        Class<?> c1 = Class.forName("Test");

        /**
         * getName()方法獲得類名
         */
        System.out.println(c1.getName());
        System.out.println();

        /**
         * getDeclaredFields()方法獲得所有屬性,包括私有屬性
         * getFields()方法只能獲得所有public屬性
         */
        Field[] fields = c1.getDeclaredFields();

        for (Field field : fields){
            System.out.println(field);
        }

        System.out.println();

        /**
         * getDeclaredField()方法獲得指定屬性,包括私有屬性
         */
        Field field = c1.getDeclaredField("name");
        System.out.println(field);
        System.out.println();

        /**
         * getDeclaredMethods()方法獲得本類的所有方法,包括私有方法
         * getMethods()方法獲得本類和父類的所有public方法
         */
        Method[] methods = c1.getDeclaredMethods();

        for (Method method : methods){
            System.out.println(method);
        }

        System.out.println();

        /**
         * getDeclaredMethod()方法獲得指定方法,包括私有方法
         * 如果由引數,需要傳入引數型別對應的Class物件
         */
        Method method = c1.getDeclaredMethod("test", String.class);
        System.out.println(method);
        System.out.println();

        /**
         * getDeclaredConstructors()方法獲得所有構造器,包括私有構造器
         * getConstructors()方法只能獲得public構造器
         */
        Constructor[] constructors = c1.getDeclaredConstructors();

        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        System.out.println();

        /**
         * getDeclaredConstructor()方法獲得指定構造器,包括私有構造器
         * 需要傳入引數型別對應的Class物件
         */
        Constructor<?> constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println(constructor);
    }
}

class Test {

    private String name;
    int age;
    int money;

    public Test(){}

    private Test(String name, int age, int money){

        this.name = name;
        this.age = age;
        this.money = money;
    }

    private void test(String name) {
        System.out.println(name + "的test()方法");
    }

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

    public String getName() {
        return name;
    }

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

建立執行時類的物件、呼叫執行時類的指定結構

  • 呼叫Class物件的newInstance()方法,建立執行時類的物件
  • 如果有無參構造器且許可權足夠,可以直接建立物件,屬性為預設值
  • 如果沒有無參構造器,需要用getDeclaredConstructor()方法獲得指定的有參構造器,傳入引數型別對應的Class物件,再通過Constructor例項化物件
  • Method、Field、Constructor物件都有setAccessible()方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {

        Class<?> c1 = Class.forName("Test");

        /**
         * 建立物件
         * 預設呼叫無參構造器的newInstance()方法建立物件,需要強制轉換一下型別
         */
        Test test = (Test) c1.newInstance();
        System.out.println(test);

        /**
         * 沒有無參構造器,可以呼叫指定的有參構造器建立物件
         * 先獲得一個有參構造器物件,再建立物件
         * 如果是私有構造器,需要用setAccessible(true)方法關閉程式的安全檢測
         */
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        constructor.setAccessible(true);
        Test test2 = (Test) constructor.newInstance("ty", 24, 10000);
        System.out.println(test2);

        /**
         * 呼叫方法
         * 先獲得一個指定方法的物件,再通過invoke()方法啟用要呼叫的方法
         * 如果是私有方法,需要用setAccessible(true)方法關閉程式的安全檢測
         */
        Method method = c1.getDeclaredMethod("setName", String.class);
        method.setAccessible(true);
        method.invoke(test2, "ttyy");
        System.out.println(test2.getName());

        /**
         * 操作屬性
         * 先獲得一個指定屬性的物件,再通過set()方法修改屬性
         * 如果是私有屬性,需要用setAccessible(true)方法關閉程式的安全檢測
         */
        Field field = c1.getDeclaredField("name");
        field.setAccessible(true);
        field.set(test2, "tttyyy");
        System.out.println(test2.getName());
    }
}

class Test {

    private String name;
    int age;
    int money;

    public Test(){}

    private Test(String name, int age, int money){

        this.name = name;
        this.age = age;
        this.money = money;
    }

    private void test(String name) {
        System.out.println(name + "的test()方法");
    }

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

    public String getName() {
        return name;
    }

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