反射这个概念在很多编程语言中都存在,像Java,C#。
在面向对象编程中,一般会先将类和方法定义好,然后创建对象显式调用方法,比如下面的例子:
public class User{
private String name;
private Date birthday;
//....
public int calculateAgeByBirthday(){
// .....
}
}
// 调用
User u = new User("jack", new Date());
u.calculateAgeByBirthday();
上面这种调用方式我们比较熟悉,不过当你想编写一些抽象框架时(框架又需要与业务定义的类进行互操作),由于你不知道业务类的成员和方法,这时反射动态获取成员变量或调用方法。
下面例子,我们利用反射将json转换为Java对象。
public static class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// 使用反射调用对象setter方法。
public static <T> T fill(Class<T> userClass, Map<String, Object> json) throws Exception {
Field[] fields = userClass.getDeclaredFields();
T user = userClass.newInstance();
for (Field field : fields) {
// 首字母大写
String name = field.getName();
char[] arr = name.toCharArray();
arr[0] = Character.toUpperCase(arr[0]);
System.out.println(new String(arr));
Method method = userClass.getDeclaredMethod("set" + new String(arr), field.getType());
Object returnValue = method.invoke(user, json.get(name));
}
return user;
}
JavaScript中Reflect
JavaScript在ES6提供了反射内置对象Reflect
,但JavaScript里面的反射和Java反射有所不同。先看下Reflect
提供的13个静态方法。
- Reflect.apply(target, thisArg, args)
- Reflect.construct(target, args)
- Reflect.get(target, name, receiver)
- Reflect.set(target, name, value, receiver)
- Reflect.defineProperty(target, name, desc)
- Reflect.deleteProperty(target, name)
- Reflect.has(target, name)
- Reflect.ownKeys(target)
- Reflect.isExtensible(target)
- Reflect.preventExtensions(target)
- Reflect.getOwnPropertyDescriptor(target, name)
- Reflect.getPrototypeOf(target)
- Reflect.setPrototypeOf(target, prototype)
Reflect.get(target, name, receiver)
Reflect.get
方法查找并返回target
对象的name
属性,如果没有该属性,则返回undefined
。
const obj = {
name: 'jack',
age: 12,
get userInfo() {
return this.name + ' age is ' + this.age;
}
}
Reflect.get(obj, '