03-反射通用编程

使用反射机制,实现执行任何类的任意方法 或 创建任意类的实体对象。

1.0 执行类任意方法

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
public class TestInvokeAnything {
public static void main(String[] args) throws Exception {
// invokeAny() 执行任何方法
// 传入:对象(Object)、方法名称(String)、形参(.class)、实参(Object)
invokeAny(
createObject("com.day.t1_factory.Student"),
"exam",
new Class[] {int.class, double.class, String.class},
2, 10, "小明"
); // public void exam(int n, double score, String name)

Object o = createObject("com.day.t1_factory.Student");
invokeAny(o, "study", null, null); // public void study()
invokeAny(o, "study", new Class[] {Integer.class}, 100); // public int study(Integer a)

}
/**
* 反射技术,执行任何方法
* @param obj Objcet类型对象
* @param methodName String类型方法名称
* @param types Class[]数组类型的types
* @param args Object类型的可变长参数
* @throws Exception
*/
public static void invokeAny(Object obj, String methodName, Class<?>[] types, Object...args) throws Exception {
Class<?> c = obj.getClass(); // 1.获取类对象
Method m = c.getDeclaredMethod(methodName, types); // 2.获得方法的对象Method
m.invoke(obj, args); // 3.执行方法
}
/**
* 反射技术,工厂设计模式
* @param className 类的全限定名
* @return 返回Object类型的对象
*/
public static Object createObject(String className) {
try {
Class<?> c = Class.forName(className);
return c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}

实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class User {
private Integer id;
private String name;
public User() {}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override
public String toString() {
return "User{" + "id=" + id + ", name='" + name + '\'' + '}';
}
}

1.1 执行类 set 方法

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
public class TestReflectMethod {
public static void main(String[] args) throws Exception {
User user = new User();
setValue(user, "id", 10);
setValue(user, "name", "hello,world");
System.out.println(user); // User{id=10, name='hello,world'}
}

/**
* 给指定对象的指定属性设置指定值
* @param obj 指定的对象
* @param fieldName 指定的属性名
* @param value 指定的属性值
*/
public static void setValue(Object obj, String fieldName, Object value) throws Exception {
Class<?> objClass = obj.getClass();
// 根据小驼峰命名规范获取 set 方法名,eg: setName
String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
System.out.println(methodName);
Field field = objClass.getDeclaredField(fieldName);
// 获取到属性类型
Class<?> fieldType = field.getType();
// 获取到 set 方法
Method method = objClass.getMethod(methodName, fieldType);
method.invoke(obj, value);
}
}

1.2 执行类 get 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class TestReflectMethodGet {
public static void main(String[] args) throws Exception {
/* 实体类的 set/get 方法通用调用示例 */
User user = new User(10, "小黑");
Object id = getValue(user, "id");
Object name = getValue(user, "name");
System.out.println(id + ":" + name); // 10:小黑
}

/**
* 从指定对象的指定属性获取属性值
* @param obj 指定对象
* @param fieldName 指定属性
* @return Object类型值
*/
public static Object getValue(Object obj, String fieldName) throws Exception {
Class<?> objClass = obj.getClass();
// 根据小驼峰命名规范获取 get 方法名,eg: getName
String methodName = "get" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
// 获取到 get 方法
Method method = objClass.getDeclaredMethod(methodName, (Class<?>[]) null);
return method.invoke(obj, (Object[]) null);
}
}

1.3 反射从文件创建对象

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
public class TestReflectConfigFile {
public static void main(String[] args) throws Exception {
User user = (User) getInstanceFromConfigFile("config.properties", "userClassName");
System.out.println(user);
}

/**
* 通过配置文件获取并创建指定键的类的实例对象
* @param fileName 配置文件名称
* @param key 配置文件中的键
* @return Object对象
*/
public static Object getInstanceFromConfigFile(String fileName, String key) throws Exception {
Properties properties = new Properties();
// 获取文件的 字节输入流
InputStream is = TestReflectConfigFile.class.getClassLoader().getResourceAsStream(fileName);
// 将流加载到 properties(map键值映射)
properties.load(is);
// 获取类全名
String className = properties.getProperty(key);
// 创建对象并返回
return Class.forName(className).newInstance();
}
}
/*
* config.properties 配置文件内容:
* userClassName=com.demo.reflect.User
*/

1.4 突破封装(一般不用)

1
2
3
4
5
6
7
8
9
// 反射:类的对象
Object o = createObject("com.day.t1_factory.Student");
// 类对象
Class<?> c = o.getClass();
Method m = c.getDeclaredMethod("calc", null); // 获取自身方法,包含私有方法
// 【注意】反射是一种底层技术,可取消语言检查,突破private封装!
// AccessibleObject类:@true 忽略Java语言访问检查 @false 反之
m.setAccessible(true);
m.invoke(o, null);

03-反射通用编程
https://janycode.github.io/2016/04/28/02_编程语言/01_Java/01_JavaSE/08_反射机制/03-反射通用编程/
作者
Jerry(姜源)
发布于
2016年4月28日
许可协议