Java反射:通过方法名调用方法

在开发中,有时希望像Javascript一样,用 object['property'] = xxx 的方式,对属性进行遍历和赋值,这就需要用到Java中的反射。

封装一个辅助类,将对象包装起来,对外暴露的是类似invokeMethod(String methodName)这样,通过方法名调用对象方法的API。下面是辅助类代码:

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.regex.Pattern;

public class ReflectObject {
// 存放需要包装的对象
private Object object;
// 对象的类
private Class cls;
// 对象的属性
private String[] props;
// 存放getter方法
private Hashtable<String, Method> getMethods = null;
// 存放setter方法
private Hashtable<String, Method> setMethods = null;
// 存放其他方法
private Hashtable<String, Method> methods = null;

/**
* 定义构造方法
* @param o 需要包装对象
*/
public ReflectObject(Object o) {
object = o;
initMethods();
}

/**
* 初始化
*/
public void initMethods() {
getMethods = new Hashtable<String, Method>();
setMethods = new Hashtable<String, Method>();
methods = new Hashtable<String, Method>();
cls = object.getClass();
Field[] fields = cls.getDeclaredFields();
props = new String[fields.length];
for(int i = 0; i < fields.length; i++) {
props[i] = fields[i].getName();
}
Method[] allMethods = cls.getMethods();
// 定义正则表达式,从方法中过滤出getter / setter 函数.
String gs = "get(\\w+)";
Pattern getM = Pattern.compile(gs);
String ss = "set(\\w+)";
Pattern setM = Pattern.compile(ss);
// 把方法中的"set" 或者 "get" 去掉
String rapl = "$1";
String param;
for (int i = 0; i < allMethods.length; ++i) {
Method m = allMethods[i];
String methodName = m.getName();
if (Pattern.matches(gs, methodName)) {
param = getM.matcher(methodName).replaceAll(rapl).toLowerCase();
getMethods.put(param, m);
} else if (Pattern.matches(ss, methodName)) {
param = setM.matcher(methodName).replaceAll(rapl).toLowerCase();
setMethods.put(param, m);
}
this.methods.put(methodName, m);
}
}

/**
* 调用object的属性property的setter方法
* @property: 属性名
* @value: 给属性赋的值
*/
public boolean setMethodValue(String property, Object value) throws Exception {
Method m = setMethods.get(property.toLowerCase());
if (m != null) {
try {
// 调用目标类的setter函数
m.invoke(object, value);
return true;
} catch (Exception ex) {
throw new Exception("对象的[" + property + "]属性的setter方法执行时报错。");
}
}
throw new Exception("未查询到对象的[" + property + "]属性的setter方法。");
}

/**
* 调用object的属性property的getter方法
* @property: 属性名
*/
public Object getMethodValue(String property) throws Exception {
Method m = getMethods.get(property.toLowerCase());
if (m != null) {
try {
// 调用目标类的getter函数
Object o = m.invoke(object);
return o;
} catch (Exception ex) {
throw new Exception("对象的[" + property + "]属性的getter方法执行时报错。");
}
}
throw new Exception("未查询到对象的[" + property + "]属性的getter方法。");
}

/**
* 调用object的methodName方法
* @methodName: 方法名
* @params: methodName接受的参数数组
*/
public Object invokeMethod(String methodName, Object[] params) throws Exception {
Method m = methods.get(methodName);
if (m == null) {
throw new Exception("未找到对象的[" + methodName + "]方法。");
}
return m.invoke(this.object, params);
}

/**
* object的getter,可以获取ReflectObject的实例包装的对象object
*/
public Object getObject() {
return object;
}

/**
* props的getter,可以获取ReflectObject的实例包装的对象object的所有属性
*/
public String[] getProps() {
return props;
}
}

调用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static void main(String[] args) {
User user = new User();
ReflectObject reflectObject = new ReflectObject(user);
reflectObject.setMethodValue("name", "张三");
reflectObject.setMethodValue("age", 16);
reflectObject.invokeMethod("say", ["李四", "你好。"]);
// 输出:张三对李四说:你好。
}

public Class User {
private String name;
private Integer age;

public void say(String targetUser, String content) {
console.log(this.name + "对" + targetUser + "说:" + content + "");
}

public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return this.age; }
public void setAge(Integer age) { this.age = age; }
}
分享到