反射

  • 什么是反射

反射是一种动态获取和操作类信息的机制,它使得我们可以在运行时动态地加载类、调用方法、访问属性等。它在一些特定的场景下非常有用,比如框架开发、配置文件解析、动态代理等。


import java.lang.reflect.Constructor;//类的构造方法,我们可以使用它获取和操作类的构造方法。
import java.lang.reflect.Field;//类的字段,我们可以使用它获取和操作类的字段。
import java.lang.reflect.Method;//类的方法,我们可以使用它获取和操作类的方法。
import java.lang.reflect.Parameter;//方法或构造方法的参数,我们可以使用它获取参数的类型和名称等信息。
  • 使用反射获取和打印User类的各种信息,包括类名、父类、实现的接口、包信息和字段信息。
package com.wz.reflect01;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;

public class Test {
    public static void main(String[] args) {
        basic();
    }

    public static void basic(){
        //获取class对象
        Class<User> clazz = User.class;
        //获取类的全限定名
        String name = clazz.getName();
        System.out.println("类的全限定名:"+name);
        //获取普通类名
        String simpleName = clazz.getSimpleName();
        System.out.println("类名:"+simpleName);
        //获取父类
        Class<? super User> superclass = clazz.getSuperclass();
        System.out.println("父类的全限定名:"+superclass.getName());
        System.out.println("父类的名字:"+superclass.getSimpleName());
        //返回一个数组,包含了该类所实现的接口的Class对象。
        Class<?>[] interfaces = clazz.getInterfaces();
        if (interfaces.length>0){
            System.out.println("类实现的接口:"+ Arrays.toString(interfaces));
        }
        //获取类的包信息
        Package clazzPackage = clazz.getPackage();
        String packageName = clazzPackage.getName();
        System.out.println("类所在的包:"+packageName);

        //获取类中的字段(public 修饰的字段)
//        Field[] fields = clazz.getFields();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field:fields){
            Class<?> type = field.getType();//获取字段类型
            String fieldName = field.getName();//获取字段名
            System.out.println("字段名"+fieldName+",字段类型"+type.getName());
        }

        //获取类中的方法(public修饰的方法)
//        Method[] methods = clazz.getMethods();
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method:methods){
            String methodName = method.getName();//获取方法的名字
            Class<?> returnType = method.getReturnType();//获取方法的返回值类型
            Parameter[] parameters = method.getParameters();//获取方法的参数列表
            StringBuilder builder = new StringBuilder();
            if (parameters !=null){
                for (Parameter p:parameters){
                    Class<?> parameterType = p.getType(); //参数类型
                    String parameterName = p.getName(); //参数的名称
                    builder.append(parameterType).append(" ").append(parameterName).append(",");
                }
                if (builder.length()>0){
                    builder.deleteCharAt(builder.length()-1);
                }
                System.out.println("方法:"+returnType+" "+methodName+"("+ builder.toString() + ")");

            }
        }


        //获取类中的公开的构造方法
//        Constructor<?>[] constructors = clazz.getConstructors();
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor: constructors){
            String constructorName = constructor.getName();
            Parameter[] parameters = constructor.getParameters();
            StringBuilder builder = new StringBuilder();
            if(parameters != null){
                for(Parameter p: parameters){
                    Class<?> parameterType = p.getType(); //参数类型
                    String parameterName = p.getName(); //参数的名称
                    builder.append(parameterType).append(" ").append(parameterName).append(",");
                }
                if(builder.length() > 0)
                    builder.deleteCharAt(builder.length()-1);
            }
            System.out.println("构造方法:" + constructorName + "(" + builder.toString() + ")");
        }

    }
}

结果:

2023年7月21日,反射_Java

//修改访问权限
public void setAccessible(boolean flag) throws SecurityException;
  • 案例: 如何使用Java反射来动态调用方法
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
package com.wz.reflect01;

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

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        User user = new User();
        user.setUsername("admin");
        user.setPassword("123456");
        System.out.println(user);

        //使用Java反射获取User类的Class对象
        Class<User> clazz = User.class;
        //使用反射创建User类的实例
        User u = clazz.newInstance();
        //通过方法名和参数列表的类型到细字节码中去找到匹配的方法
        Method method = clazz.getMethod("setUsername", String.class);
        method.invoke(u,"admin");
        method = clazz.getMethod("setPassword", String.class);
        method.invoke(u,"123456");
        System.out.println(u);


        User u2 = clazz.newInstance();
        //获取类中定义的字段
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
//                String fieldName = field.getName();
            // username => setUsername = set + U + sername
//                String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
//                Class<?> fieldType = field.getType();
//                Method m = clazz.getMethod(methodName, fieldType);
//                m.invoke(u2, "test");
            //私有的字段不能够直接访问,那么我们可以先拿到访问的权限,即设置这个字段可访问
            field.setAccessible(true);
            //直接为字段赋值
            field.set(u2, "test");
        }
        System.out.println(u2);

    }
}

结果:

2023年7月21日,反射_反射_02