小言_互联网的博客

Springboot内置的工具类之ReflectionUtils

263人阅读  评论(0)

前言

        ReflectionUtils应该是Springboot内置工具类梳理的最后一篇了,可能很多人都没有听说过这个工具类,这个类封装的是一些与java反射相关的静态工具方法。可能很多人也知道反射,却不怎么经常使用反射。其实反射是一个很有用的技术点,我认为是可以和AOP比肩的,甚至有过之而不及。大家都知道AOP是面向切面编程,可以在定义的切面前、后执行一些操作,但是反射更厉害,它可以在程序运行时,对已装载的任意类的属性和方法进行操作,这就是java的反射机制。

ReflectionUtils

        org.springframework.util.ReflectionUtils中包含的静态方法其实有很多,主要分为两类:对类中属性的操作和对类中方法的操作。

对属性的操作

获取属性字段

 Field findField(Class clazz, String name),在类中查找指定属性。


  
  1. @Test
  2. public void test1( ){
  3. //查找属性字段realName
  4. Field realName = ReflectionUtils. findField( Employee. class, "realName");
  5. Assert. notNull(realName, "获取员工类的姓名属性失败");
  6. }

Field findField(Class clazz, String name, Class type),更精确的在类中查找指定属性,可以在指定属性的类型。


  
  1. @Test
  2. public void test2( ){
  3. //查找属性字段realName,类型是String
  4. Field realName = ReflectionUtils. findField( Employee. class, "realName", String. class);
  5. Assert. notNull(realName, "获取员工类的姓名属性失败");
  6. }

设置属性字段的值

Object getField(Field field, Object target),获取 target 对象的 field 属性值。


  
  1. @Test
  2. public void test3 () {
  3. //声名一个对象,姓名是zhangsan
  4. Employee zhangsan = new Employee( "zhangsan");
  5. //获取Employee类中的realName属性字段
  6. Field field = ReflectionUtils.findField(Employee.class, "realName");
  7. //取消realName属性的private权限控制
  8. ReflectionUtils.makeAccessible(field);
  9. //获取员工对象的姓名字段的值
  10. Object value = ReflectionUtils.getField(field, zhangsan);
  11. Assert.isTrue(value.equals( "zhangsan"), "员工zhangsan的姓名字段取值失败" );
  12. }

void setField(Field field, Object target, Object value),可以设置 target 对象的 field 属性值,值为 value。


  
  1. @Test
  2. public void test4 () {
  3. Employee zhangsan = new Employee( "zhangsan");
  4. //获取Employee类中的realName属性字段
  5. Field field = ReflectionUtils.findField(Employee.class, "realName");
  6. //取消realName属性的private权限控制
  7. ReflectionUtils.makeAccessible(field);
  8. //把员工对象zhangsan的姓名字段值设置为zhangsan_v2
  9. ReflectionUtils.setField(field, zhangsan, "zhangsan_v2");
  10. Object value = ReflectionUtils.getField(field, zhangsan);
  11. Assert.isTrue(value.equals( "zhangsan_v2"), "员工zhangsan的姓名字段取值失败" );
  12. }

void shallowCopyFieldState(Object src, Object dest),如果两个对象是同一个类的实现,且希望把一对象的值复制到另外一个对象上,可以使用这个方法,src是源对象,dest是目标对象。


  
  1. @Test
  2. public void test5 () {
  3. Employee zhangsan = new Employee( "zhangsan");
  4. Employee tmp = new Employee();
  5. //把对象zhangsan的值复制到对象tmp上,这里要注意,复制的对象类型要相同
  6. ReflectionUtils.shallowCopyFieldState(zhangsan, tmp);
  7. Assert.isTrue(tmp.getRealName().equals( "zhangsan"), "对象的属性复制失败了" );
  8. }

void makeAccessible(Field field),取消java的权限控制检查,方便private私有访问权限的操作。


  
  1. @Test
  2. public void test4( ) {
  3. Employee zhangsan = new Employee( "zhangsan");
  4. //取消realName属性的private权限控制
  5. ReflectionUtils. makeAccessible(field);
  6. }

void doWithFields(Class clazz, ReflectionUtils.FieldCallback fc),可以对类的每个属性执行 回调方法,简单的理解就是可以定义一个回调方法,在对类的属性操作完后,回调方法内的逻辑就会被执行。另外还有两个方法,功能也很类似:void doWithFields(Class clazz, ReflectionUtils.FieldCallback fc,ReflectionUtils.FieldFilter ff),不仅有回调方法,还可以增加过滤的逻辑;void doWithLocalFields(Class clazz, ReflectionUtils.FieldCallback fc),只对本类的属性可以执行回调方法,不包括父类的。举个例子,简单的理解一下,实在理解不了就放弃吧,因为我也觉得这个确实有点鸡肋。假如员的性别在程序中是以1和0进行区分,对外展示的时候要转换为“男”和“女”:


  
  1. public class SexFieldCallBack< T> implements ReflectionUtils.FieldCallback{
  2. private Object obj;
  3. private Integer sexFlag= -1;
  4. public SexFieldCallBack(Object obj) {
  5. this.obj = obj;
  6. }
  7. @Override
  8. public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
  9. field.setAccessible( true);
  10. if (field.getName(). equals( "sexFlag")) {
  11. Object value = field. get(obj);
  12. this.sexFlag= ((Integer) value);
  13. }
  14. if(field.getName(). equals( "sex")){
  15. if ( 1== this.sexFlag) {
  16. field. set(obj, "男");
  17. }
  18. if ( 0== this.sexFlag) {
  19. field. set(obj, "女");
  20. }
  21. }
  22. }
  23. }

  
  1. @Test
  2. public void test6() throws IllegalAccessException, InstantiationException {
  3. Employee employee = Employee. class.newInstance();
  4. employee.setRealName( "zhangsan");
  5. //性别标志位,1:男,0:女
  6. employee.setSexFlag( 1);
  7. ReflectionUtils.doWithFields(Employee. class, new SexFieldCallBack(employee) );
  8. Assert.isTrue( "男". equals(employee.getSex()), "性别转换失败了");
  9. }

对方法的操作


  
  1. @Data
  2. public class Employee implements Serializable {
  3. private String realName;
  4. public void hello( String name) {
  5. System. out. println(name + ",你好!我是" + this. realName);
  6. }
  7. public void say( String name) {
  8. System. out. println(name + ",你好!我是" + this. realName);
  9. }
  10. public String hello( String name, Boolean isReturn) {
  11. String msg = name + ",你好!我是" + this. realName;
  12. if (isReturn) {
  13. System. out. println(msg);
  14. return msg;
  15. }
  16. return null;
  17. }
  18. }

获取方法

Method findMethod(Class clazz, String name),在类中查找指定名字方法


  
  1. @Test
  2. public void test7 () throws IllegalAccessException, InstantiationException, InvocationTargetException {
  3. //查找类中的hello方法
  4. //这里要注意如果类中有方法名相同的重载方法时,一要要用下面的方法,把参数的类型给带上
  5. //如果不是重载方法,用这个也没问题
  6. Method say = ReflectionUtils.findMethod(Employee.class, "say");
  7. Employee employee = Employee.class.newInstance();
  8. employee.setRealName( "zhangsan");
  9. say.invoke(employee, "lisi");
  10. }

Method findMethod(Class clazz, String name, Class... paramTypes),有的时候同一个类可能会有多个方法名相同,形参数不同的重载方法,可以使用这个方法更精确的在类中找到指定方法;


  
  1. @Test
  2. public void test8() throws IllegalAccessException, InstantiationException, InvocationTargetException {
  3. Method hello = ReflectionUtils.findMethod(Employee. class, "hello",String. class,Boolean. class);
  4. Employee employee = Employee. class.newInstance();
  5. employee.setRealName( "zhangsan");
  6. //执行employee对象的hello方法
  7. Object msg = hello.invoke(employee, "lisi", true);
  8. System. out.println(msg);
  9. }

Method[] getAllDeclaredMethods(Class leafClass),获得类中所有方法,包括继承而来的。


  
  1. @Test
  2. public void test9() {
  3. //获取类中所有的方法,包括继承而来的
  4. Method[] methods = ReflectionUtils.getAllDeclaredMethods(Employee. class);
  5. for (Method o : methods) {
  6. System. out.println(o.getName());
  7. }
  8. }

执行方法

Object invokeMethod(Method method, Object target),执行无参数的方法;

Object invokeMethod(Method method, Object target, Object... args),执行有参数的方法

void makeAccessible(Method method),如果是私有方法,可以取消 Java 权限检查,以便后续执行该私有方法


  
  1. @Test
  2. public void test10() throws IllegalAccessException, InstantiationException, InvocationTargetException {
  3. //获取set方法
  4. Method setRealName = ReflectionUtils.findMethod(Employee. class, "setRealName", String. class);
  5. //反射实例化一个对象
  6. Employee employee = Employee. class.newInstance();
  7. //放开权限检查
  8. ReflectionUtils.makeAccessible(setRealName);
  9. //执行set方法
  10. setRealName.invoke(employee, "zhangsan");
  11. //获取get方法
  12. Method getRealName = ReflectionUtils.findMethod(Employee. class, "getRealName");
  13. //执行get方法
  14. Object result = getRealName.invoke(employee);
  15. Assert.isTrue(result. equals( "zhangsan"), "getRealName方法执行失败");
  16. }


转载:https://blog.csdn.net/fox9916/article/details/128346911
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场