1 前言
spring-core依赖中,带有反射工具类ReflectionUtils,导包如下:
import org.springframework.util.ReflectionUtils;
(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();
}
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();
}
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'}