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 +
                '}';
    }
}