Spring:ReflectionUtils工具类使用一:Field

Spring:ReflectionUtils工具类使用一:Field

1 前言

spring-core依赖中,带有反射工具类ReflectionUtils,导包如下:

import org.springframework.util.ReflectionUtils;

在这里插入图片描述
2 Field相关使用

(1)ReflectionUtils.makeAccessible、ReflectionUtils.findField使用:

实际上,ReflectionUtils.makeAccessible本质就是调用field.setAccessible(true),让非public修饰的字段,可以操作如protected、private修饰的字段。如下,ReflectionUtils.findField不使用ReflectionUtils.makeAccessible也是可以的,但是ReflectionUtils.getField是需要使用的。
在这里插入图片描述
新建注解类MyFruit:

package com.xiaoxu.annotation;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyFruit {
    String fruitName();
    int number();
}

新建一个DTO类:FruitDTO:
在这里插入图片描述

package com.xiaoxu.dto;

import com.xiaoxu.annotation.MyFruit;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xiaoxu
 * @date 2022-02-14
 * Ymybatis:com.xiaoxu.dto.FruitDto
 */
public class FruitDto {
    @MyFruit(fruitName = "荔枝",number = 1)
    private String one;

    @MyFruit(fruitName = "菠萝",number = 2)
    private String two;

    public static void main(String[] args) {
        Class<FruitDto> clazz = FruitDto.class;
        Field[] f = clazz.getDeclaredFields();
        System.out.println(Arrays.toString(f));
        Map<Integer,Field> m = new HashMap<>();
        for (Field field : f) {
            System.out.println("*********开始*********");
            System.out.printf("我是field:%s%n",field);
            String fieldName = field.getName();
            System.out.printf("我是字段名:%s%n",fieldName);
            Field field1 = ReflectionUtils.findField(clazz, fieldName);
            if(field1 !=null){
                ReflectionUtils.makeAccessible(field1);
            }
            System.out.printf("ReflectionUtils的findField方法获取字段:%s%n",field1);
            // 如果字段具有MyFruit注解
            if(field.isAnnotationPresent(MyFruit.class)){
                MyFruit myFruit = field.getAnnotation(MyFruit.class);
                System.out.printf("字段field调用getAnnotation获取注解:%s%n",myFruit);
                System.out.printf("map.put返回值为null,说明key不重复:%s%n",m.put(myFruit.number(),field));
                System.out.printf("map.put返回值为value(这里是Filed的name),说明key重复了:%s%n",m.put(myFruit.number(),field).getName());
                System.out.printf("获取注解的fruitName:%s%n",myFruit.fruitName());
                System.out.printf("获取注解的number:%s%n",myFruit.number());
            }
            System.out.println("*********结束*********");
        }
        System.out.printf("字典如下:%s%n",m);
        for(Map.Entry<Integer,Field> e:m.entrySet()){
            System.out.printf("字典的key:%s,value:%s%n",e.getKey(),e.getValue());
            System.out.println(e.getValue().getAnnotation(MyFruit.class).fruitName());
            System.out.println(e.getValue().getAnnotation(MyFruit.class).number());
        }
    }
}

执行结果如下:

[private java.lang.String com.xiaoxu.dto.FruitDto.one, private java.lang.String com.xiaoxu.dto.FruitDto.two]
*********开始*********
我是field:private java.lang.String com.xiaoxu.dto.FruitDto.one
我是字段名:one
ReflectionUtils的findField方法获取字段:private java.lang.String com.xiaoxu.dto.FruitDto.one
字段field调用getAnnotation获取注解:@com.xiaoxu.annotation.MyFruit(fruitName=荔枝, number=1)
map.put返回值为null,说明key不重复:null
map.put返回值为value(这里是Filed的name),说明key重复了:one
获取注解的fruitName:荔枝
获取注解的number:1
*********结束*********
*********开始*********
我是field:private java.lang.String com.xiaoxu.dto.FruitDto.two
我是字段名:two
ReflectionUtils的findField方法获取字段:private java.lang.String com.xiaoxu.dto.FruitDto.two
字段field调用getAnnotation获取注解:@com.xiaoxu.annotation.MyFruit(fruitName=菠萝, number=2)
map.put返回值为null,说明key不重复:null
map.put返回值为value(这里是Filed的name),说明key重复了:two
获取注解的fruitName:菠萝
获取注解的number:2
*********结束*********
字典如下:{1=private java.lang.String com.xiaoxu.dto.FruitDto.one, 2=private java.lang.String com.xiaoxu.dto.FruitDto.two}
字典的key:1,value:private java.lang.String com.xiaoxu.dto.FruitDto.one
荔枝
1
字典的key:2,value:private java.lang.String com.xiaoxu.dto.FruitDto.two
菠萝
2

(2)ReflectionUtils.doWithFields使用:
在这里插入图片描述
注解MFruit:

package com.xiaoxu.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MFruit {
    String name();
    long num();
}

在这里插入图片描述
dto下新建PreciousFruit类:

package com.xiaoxu.dto;

import com.xiaoxu.annotations.MFruit;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xiaoxu
 * @date 2022-02-14 22:26
 * mybatis_learn:com.xiaoxu.dto.PreciousFruit
 */
public class PreciousFruit {
    @MFruit(name = "芒果",num = 1)
    private String fruitOne;

    @MFruit(name = "猕猴桃",num = 2)
    private String fruitTwo;

    @MFruit(name = "香蕉",num = 3)
    public String fruitThree;

    @MFruit(name = "砂糖橘",num = 4)
    protected String fruitFour;

    public static Map<Long,Field> injectMethod(){
        Map<Long,Field> m = new HashMap<>();
        ReflectionUtils.doWithFields(PreciousFruit.class,
                // FieldCallback是一个函数式接口,所以可以使用lambda表达式,
                // 也可以使用方法引用,或者直接new 重写接口的doWith方法
                new ReflectionUtils.FieldCallback() {
                    @Override
                    public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
                        System.out.println("我是回调,哈哈哈哈");
                        if(field.isAnnotationPresent(MFruit.class)){
                            System.out.printf("字段:%s;具有注解MFruit%n",field);
                            long number = field.getAnnotation(MFruit.class).num();
                            if(m.put(number,field)!=null){
                                System.out.println("该水果number重复,跳过");
                            }
                        }
                        System.out.println("********");
                    }
                });
        return m;
    }

    public static void main(String[] args) {
        Map<Long, Field> longFieldMap = PreciousFruit.injectMethod();
        longFieldMap.forEach((k,v)->System.out.printf("map的key:%s,value:%s%n",k,v));
    }
}

执行结果:

我是回调,哈哈哈哈
字段:private java.lang.String com.xiaoxu.dto.PreciousFruit.fruitOne;具有注解MFruit
********
我是回调,哈哈哈哈
字段:private java.lang.String com.xiaoxu.dto.PreciousFruit.fruitTwo;具有注解MFruit
********
我是回调,哈哈哈哈
字段:public java.lang.String com.xiaoxu.dto.PreciousFruit.fruitThree;具有注解MFruit
********
我是回调,哈哈哈哈
字段:protected java.lang.String com.xiaoxu.dto.PreciousFruit.fruitFour;具有注解MFruit
********
map的key:1,value:private java.lang.String com.xiaoxu.dto.PreciousFruit.fruitOne
map的key:2,value:private java.lang.String com.xiaoxu.dto.PreciousFruit.fruitTwo
map的key:3,value:public java.lang.String com.xiaoxu.dto.PreciousFruit.fruitThree
map的key:4,value:protected java.lang.String com.xiaoxu.dto.PreciousFruit.fruitFour

Process finished with exit code 0

(3)ReflectionUtils.getField使用:

ReflectionUtils.getField本质是调用的field.get(target),getField获取对象该字段的值时,引用类型若未使用setter赋值,那么默认值就是null。另外,ReflectionUtils.getField使用时,若是protected或者private修饰的字段,需先使用ReflectionUtils.makeAccessible(field)。

package com.xiaoxu.dto;

import com.xiaoxu.annotation.MyFruit;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * @author xiaoxu
 * @date 2022-02-15 21:31
 * mybatis_learn:com.xiaoxu.dto.FruitDto
 */
public class FruitDto {
    @MyFruit(fruitName = "荔枝",number = 1)
    public String one;
    @MyFruit(fruitName = "菠萝",number = 2)
    private String two;
    @MyFruit(fruitName = "车厘子",number = 3)
    protected String three;

    public void setOne(String one) {
        this.one = one;
    }

    public void setTwo(String two) {
        this.two = two;
    }

    public void setThree(String three) {
        this.three = three;
    }

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class<FruitDto> clazz = FruitDto.class;
        FruitDto cls = clazz.newInstance();
        Field[] fields = clazz.getDeclaredFields();
        cls.setThree("nihao");
        for (Field field : fields) {
            System.out.printf("我是字段%s%n",field);
            System.out.printf("我是字段的修饰符:%s%n",field.getModifiers());
            switch(field.getModifiers()){
                case 1:
                    System.out.println("我是public");
                    Object filed1 = ReflectionUtils.getField(field,cls);
                    System.out.printf("我是field:%s%n",filed1);
                    break;
                case 2:
                    System.out.println("我是private");
                    ReflectionUtils.makeAccessible(field);
                    Object filed2 = ReflectionUtils.getField(field,cls);
                    System.out.printf("我是field:%s%n",filed2);
                    break;
                case 4:
                    System.out.println("我是protected");
                    ReflectionUtils.makeAccessible(field);
                    Object filed3 = ReflectionUtils.getField(field,cls);
                    System.out.printf("我是field:%s%n",filed3);
                    break;
                default:
                    System.out.println("暂时只支持public、protected、private.");
            }
            if(Modifier.isProtected(field.getModifiers())){
                System.out.println("我是保护的");
                ReflectionUtils.makeAccessible(field);
                Object field1 = ReflectionUtils.getField(field, cls);
                System.out.println(field1);
            }
            System.out.println("****************");
        }
    }
}

执行结果:

我是字段public java.lang.String com.xiaoxu.dto.FruitDto.one
我是字段的修饰符:1
我是public
我是field:null
****************
我是字段private java.lang.String com.xiaoxu.dto.FruitDto.two
我是字段的修饰符:2
我是private
我是field:null
****************
我是字段protected java.lang.String com.xiaoxu.dto.FruitDto.three
我是字段的修饰符:4
我是protected
我是field:nihao
我是保护的
nihao
****************

(4)ReflectionUtils.setField使用:

实体类中重写toString便于观察,无需加入setter方法。且使用ReflectionUtils.setField前,也需要为private、protected修饰的字段执行setAccessible(ture)操作。

package com.xiaoxu.dto;

import com.xiaoxu.annotations.MyFruit;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
 * @author xiaoxu
 * @date 2022-02-16 22:31
 * mybatis_learn:com.xiaoxu.dto.FruitDto2
 */
public class FruitDto2 {
    @MyFruit(fruitName = "牛油果",number = 1)
    public String one;

    @MyFruit(fruitName = "葡萄",number = 2)
    private String two;

    @MyFruit(fruitName = "桃子",number = 3)
    protected String three;

    @Override
    public String toString() {
        return "水果2{" +
                "one='" + one + '\'' +
                ", two='" + two + '\'' +
                ", three='" + three + '\'' +
                '}';
    }

    public static void main(String[] args) throws IllegalAccessException, InstantiationException {
        Class<? extends FruitDto2> clazz = FruitDto2.class;
        FruitDto2 f = clazz.newInstance();
        Arrays.stream(clazz.getDeclaredFields()).forEach(field->{
            System.out.println(field);
            if(Modifier.isPrivate(field.getModifiers())||Modifier.isProtected(field.getModifiers())){
                ReflectionUtils.makeAccessible(field);
            }
            ReflectionUtils.setField(field,f,"one");
        });
        System.out.println(f);
    }
}

结果如下:

public java.lang.String com.xiaoxu.dto.FruitDto2.one
private java.lang.String com.xiaoxu.dto.FruitDto2.two
protected java.lang.String com.xiaoxu.dto.FruitDto2.three
水果2{one='one', two='one', three='one'}
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值