java反射工具

  

背景

  
  反射其实使用上镜率不高,但是有些功能如果用反射来写会更通用。当然考量用不用为此写一个工具还是依据三次原则,即一样类似的代码如果写了3次以上,那就要考虑抽象一下了。比如这次有个需求是做报表生成excel下载,每次手动生成excel写起来很是麻烦,于是就写了个反射专门处理。用一个对象的属性作为excel的列名,一个对象就是一行。这样直接使用查询出的List转换一下就可以生成excel下载了,很是方便。
  当然本文并不是写这个生成excel的工具,而是一个更基本的工具。关于反射的基本知识就不写了,浪费篇幅。

原因

  
  为什么要写这个工具,就不得不说一下java.lang.reflect 包下的2个方法:

  • getField
  • getDeclaredField
      第一个,getField方法 这个可以拿到该类 以及 父类中 所有 public 的属性 ,但是其他作用域(private,protect等)的属性拿不到。而第二个,getDeclaredField则可以获得 该类所有作用域的属性,但是无法从父类、超类等 中获得属性。
      由于这2个方法都有局限性:比如我要拿到 一个类包括其继承的父类的 所有作用域的属性,这就尴尬了。而写这个工具类就是解决这个问题。

util

   主要是用了递归向上查询获取,Object.class 作为返回标记。写的时候用到了lambda,所以得用java8。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
*
* @ClassName: ReflectUtil 反射工具
* @Description: java 本身的反射方法有所局限,所以写个简单扩展,方便使用
*
* @getField: 这个可以拿到该类 以及 父类中 所有 public 的属性 ,但是其他作用域拿不到
* @getDeclaredField : 这个可以拿到类中所有作用域的属性 但是不能拿到父类中的属性
*
* @author: chenhaoyu
* @date: Jun 27, 2019 11:08:07 AM
*/
public class ReflectUtil {

/**
*
* @Description: 不受父类,作用域局限 获得 某个类中 指定的属性 如果没有则返回null.
* @param clazz 目标对象的类
* @param fieldname 所需拿的属性名
* @return
* @author: chenhaoyu
* @throws NoSuchFieldException
* @time:Jun 26, 2019 6:26:36 PM
*/
public static Field getTargetField(Class<?> clazz, String fieldname) throws NoSuchFieldException {
if (clazz == Object.class) {
throw new NoSuchFieldException(fieldname);
}
Field f = null;
try {
// System.out.println(clazz.getSimpleName() +" 中找到:"+fieldname);
f = clazz.getDeclaredField(fieldname);
} catch (NoSuchFieldException e) {
// System.out.println(clazz.getSimpleName() +" 中未找到:"+fieldname+",向上寻找 "+clazz.getSuperclass().getSimpleName());
f = getTargetField(clazz.getSuperclass(), fieldname);
}
f.setAccessible(true);
return f;
}

/**
*
* @Description: 不受父类,作用域局限 获得 某个类中 所有的属性
* @param clazz 目标对象的类
* @return
* @author: chenhaoyu
* @time:Jun 27, 2019 11:11:59 AM
*/
public static List<Field> getAllFields(Class<?> clazz) {
return getAllFields(clazz, null);
}

/**
*
* @Description:内部方法 对外不可见 上面那个方法是将本方法封装了一下,可以直接获得一个list
* @param clazz
* @param list
* @return
* @author: chenhaoyu
* @time:Jun 27, 2019 11:13:26 AM
*/
private static List<Field> getAllFields(Class<?> clazz, List<Field> list) {
if (list == null) {
list = new ArrayList<>();
}
if (clazz == Object.class) {
return list;
} else {
List<Field> temp = Arrays.asList(clazz.getDeclaredFields());
temp.forEach(f -> f.setAccessible(true));
list.addAll(temp);
getAllFields(clazz.getSuperclass(), list);
return list;
}
}

/***
*
* @Description:查看某个class中所有的属性
* @param clazz
* @author: chenhaoyu
* @time:Jun 27, 2019 11:17:17 AM
*/
public static void lookClass(Class<?> clazz) {
List<Field> list = getAllFields(clazz);
list.stream().map(f -> f.getName()).forEach((System.out::println));
}

/**
*
* @Description:查看某个对象中所有的属性
* @param obj
* @author: chenhaoyu
* @time:Jun 27, 2019 11:17:39 AM
*/
public static void lookObject(Object obj) {
List<Field> list = getAllFields(obj.getClass());
for (Field field : list) {
try {
System.out.println(field.getType() + " " + field.getName() + " : " + field.get(obj));
} catch (Exception e) {
}
}
}
}

结尾

  主要还是上面的util代码,就几个递归也没啥好说的。希望能帮到有需要的人吧。