reflect反射

63 阅读2分钟

概念

在运行时获取类字节码文件对象,然后解析类的构造器、变量、方法。

类(Class)对象 方法(Method)对象 字段(Field)对象

获取类对象,类对象去getConstuctor Method Fields

获取Class类对象的三种方式

public class Test {
    public static void main(String[] args) throws Exception {
        // 1、Class类中的一个静态方法:forName(全限名:包名 + 类名)
        Class c = Class.forName("com.itheima.d2_reflect_class.Student");
        System.out.println(c); // Student.class

        // 2、类名.class
        Class c1 = Student.class;
        System.out.println(c1);

        // 3、对象.getClass() 获取对象对应类的Class对象。
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    }
}

获取构造器

@Test
public void getConstructors(){
    // a.第一步:获取类对象
    Class c = Student.class;
    // b.提取类中的全部的构造器对象(这里只能拿public修饰)
    Constructor[] constructors = c.getConstructors();
    // c.遍历构造器
    for (Constructor constructor : constructors) {
        System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());
    }
}

获取成员变量

@Test
public void getDeclaredFields(){
    // a.定位Class对象
    Class c = Student.class;
    // b.定位全部成员变量
    Field[] fields = c.getDeclaredFields();
    // c.遍历一下
    for (Field field : fields) {
        System.out.println(field.getName() + "==>" + field.getType());
    }
}

赋值和取值

@Test
public void setField() throws Exception {
    // a.反射第一步,获取类对象
    Class c = Student.class;
    // b.提取某个成员变量
    Field ageF = c.getDeclaredField("age");
    ageF.setAccessible(true); // 暴力打开权限
    // c.赋值
    Student s = new Student();
    ageF.set(s , 18);  // s.setAge(18);
    System.out.println(s);
    // d、取值
    int age = (int) ageF.get(s);
    System.out.println(age);
}

方法

public void getDeclardMethod() throws Exception {
    // a.获取类对象
    Class c = Dog.class;
    // b.提取单个方法对象
    Method m = c.getDeclaredMethod("eat");
    Method m2 = c.getDeclaredMethod("eat", String.class);
    // 暴力打开权限了
    m.setAccessible(true);
    m2.setAccessible(true);
    // c.触发方法的执行
    Dog d = new Dog();
    // 注意:方法如果是没有结果回来的,那么返回的是null.
    Object result = m.invoke(d);
    System.out.println(result);
    // 原本是对象去调用函数,现在是函数去催促对象
    Object result2 = m2.invoke(d, "骨头");
    System.out.println(result2);
}

作用

反射可以给约定了类型的集合填入其他类型的元素

编译成Class文件泛型会自动擦除

image.png

实例-反射做通用框架

image.png

public static void save(Object obj){
    try (
            PrintStream ps = new PrintStream(new FileOutputStream("junit-ref-anno-proxy/src/data.txt", true));
    ){
        // 1、提取这个对象的全部成员变量:只有反射可以解决
        Class c = obj.getClass();  //   c.getSimpleName()获取当前类名   c.getName获取全限名:包名+类名
        ps.println("================" + c.getSimpleName() + "================");

        // 2、提取它的全部成员变量
        Field[] fields = c.getDeclaredFields();
        // 3、获取成员变量的信息
        for (Field field : fields) {
            String name = field.getName();
            // 提取本成员变量在obj对象中的值(取值)
            field.setAccessible(true);
            String value = field.get(obj) + "";
            ps.println(name  + "=" + value);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

分析: 以object为形参,接收任意类 getDeclaredFields()获取成员变量 接着就遍历就行了