反射有什么用?

能在程序运行期间动态加载一个完全未知的类

显然可以提高java灵活性和增加应用场景

核心

Class c=Class.forName("reflection.User");

这里声明一个类的对象(注意Class中c是大写,class是关键字)
然后获取路径(包名+类名),这样c虽然不是User类,但是就相当于一面镜子
可以通过c获得对象,所以称为“反射”

说明

下面举例说明,这是包的结构,这三个类我们一一构造

首先我们构建一个User类,作为实验

package reflection;

public class User {
    private String name="cs";
    private String sex;
    private int age;
    public String address;
    public User(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public User(){};
    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public int getAge() {
        return age;
    }

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

注意:
1、需要反射的对象,我们称为JavaBean,他一定要有一个无参构造器(反射通过无参构造器获取对象)
2、我们给name赋了初值cs,address没有任何方法;作为对照

Test.java

package reflection;

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

public class Test {
    public static void main(String [] args) throws NoSuchMethodException {
        String path="reflection.User";
        try {
            Class <?>clazz=Class.forName(path);
            System.out.println(clazz.getSimpleName());
            
            //Field[] fields=clazz.getFields();//只能获得public修饰的属性
            Field[] fields=clazz.getDeclaredFields();//可以获得所有属性
            System.out.println(fields.length);

            Method[] methods=clazz.getDeclaredMethods();
            for(Method method:methods){
                System.out.println("方法有"+method);
                
            }

            Constructor [] constructors=clazz.getDeclaredConstructors();
            Constructor c=clazz.getDeclaredConstructor(String.class,String.class,int.class);
            System.out.println("获得构造器"+c);
            for (Constructor constructor:constructors){
                System.out.println("构造器有"+constructor);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

这里会看到很多陌生的方法 field,method,constructor
他们分别对应类中的属性,方法,构造器
也就是说,可以通过这三个方法获取到类

这是打印结果,打印了属性的数量,方法的具体名称,构造器,其中获得构造器表示在getDeclaredConstructor方法中加入构造器名和对应的参数属性(因为会有同名构造器),就可以获得目标构造器,也可以通过这个方法获得目标普通方法

当然了上面的虽然能获取,但是其实没有太多作用,我们需要的是获取具体内容并修改

Test2.java

package reflection;


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

//这个注解可以避免代码警告
@SuppressWarnings("all")
public class Test2 {
    public static void main(String[] args)  {
        String path="reflection.User";
       
        User user= null;
        //以下方法都是反射API
        try {
        
            Class clazz=Class.forName(path);
            //通过newInstance(),调用无参构造方法,获取到user的对象.
            //因此javabean必须要有无参构造方法
            user = (User) clazz.getDeclaredConstructor().newInstance();
            //也可以调用其他构造器
            //先构造目标构造器,然后通过目标构造器获得相应的类的对象,以及修改属性
            Constructor constructor=clazz.getDeclaredConstructor(String.class,String.class,int.class);
            user= (User) constructor.newInstance("陈松","男",18);
            System.out.println(user.getName());
            
            //调用普通方法
            //用method设置需要调用的方法名和类型(避免重载的同名方法混淆),
            User u3= (User) clazz.getDeclaredConstructor().newInstance();
            Method method=clazz.getDeclaredMethod("setName", String.class);
            //然后用invoke激活该方法,参数是对象名和方法参数
            method.invoke(u3,"陈松u3");
            System.out.println(u3.getName());
            
            
            //调用并操作属性,使用field获取对应属性,然后跳过检测,在field中设置新数据
            User u4=(User)clazz.getDeclaredConstructor().newInstance();
            Field field=clazz.getDeclaredField("name");
            //我们这里是操作私有属性,所以是用setAccessible方法跳过私有检测
            field.setAccessible(true);
            field.set(u4,"陈松u4");
            System.out.println(u4.getName());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

在代码中我已经写了大量注释,就不再赘述
这是输出