前几天,笔试遇到一道题目:“一串json格式文字,通过类反射机制设置为对应对象属性”;就此找了一些资料,自己实现下。
先理解下 java 的反射机制是什么意思先。
下面这段 转载自:https://blog.csdn.net/ryelqy/article/details/79905355
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。
下面的实现是两种情况
1,如果是基础类型,则通过反射对应的set方法,调用设置属性值。
2,如果是包装类和String(暂时只想这个),需要特殊处理下
3,如果是其他类,则递归处理。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Locale;
/**
* 通过类发射,用json设置属性
*/
public class TestInvoke {
@SuppressWarnings("rawtypes")
public static void main(String args[]) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
String jsonStr = "{\n" +
" \"name\": \"name1\",\n" +
" \"age\": 30,\n" +
" \"child\": {\n" +
" \"sex\": 1\n" +
" }\n" +
"}";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println(jsonObject.toJSONString());
People people = new People();
getFieldByClass(people, jsonObject);
System.out.println("======================================");
System.out.println("设置后的bean的值为:\n" + people.getName() + "\t" + people.getAge());
System.out.println(JSON.toJSON(people).toString());
}
/**
* 设置实例类的属性
*
* @param obj 要被赋值的实例类
* @param field 要被赋值的属性
* @param valueObj 要被赋值的属性的值
*/
private static void setProperty(Object obj, Field field, Object valueObj) {
try {
Class<?> clazz = obj.getClass();
//获取类的setXxx方法,xxx为属性
Method method = clazz.getDeclaredMethod(
"set"
+ field.getName().substring(0, 1)
.toUpperCase(Locale.getDefault())
+ field.getName().substring(1), field.getType());
//设置set方法可访问
method.setAccessible(true);
//调用set方法为类的实例赋值
method.invoke(obj, valueObj);
} catch (Exception e) {
e.printStackTrace();
}
}
static Object getFieldByClass(Object bean, JSONObject jsonObject)
throws IllegalAccessException, InstantiationException {
Class userCla = bean.getClass();
/*
* 得到类中的所有属性集合
*/
Field[] fs = userCla.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field field = fs[i];
field.setAccessible(true); // 设置些属性是可以访问的
Object val = field.get(bean);// 得到此属性的值
System.out.println("name:" + field.getName() + "\t value = " + val);
Class<?> typeClazz = field.getType();
if (typeClazz.isPrimitive()) {
setProperty(bean, field, jsonObject.get(field.getName()));
} else {
Object typeObj = typeClazz.newInstance();
if (typeObj instanceof String) {
System.out.println(field.getType() + "\t是String");
field.set(bean, jsonObject.getString(field.getName())); // 给属性设值
} else {
System.out.println(field.getType() + "\t");
field.set(bean, getFieldByClass(typeObj, jsonObject.getJSONObject(field.getName())));
}
}
}
return bean;
}
}
class People {
private String name;
private int age;
private Child child;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
}
class Child {
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
遇到的问题,包装类那些无法实例化
Class.newInstance() 这里出现问题了
参考:https://blog.csdn.net/fxkcsdn/article/details/76738048
这里的判断加点东西,判断包装类的情况
if (typeClazz.isPrimitive()) {
setProperty(bean, field, jsonObject.get(field.getName()));
} else if (field.getGenericType().toString().equals(
"class java.lang.Integer")) {
// 如果类型是Integer
Method method = (Method) bean.getClass().getMethod(
"set" + getMethodName(field.getName()), field.getType());
System.out.println(field.getType() + "\t是Integer ; value " + jsonObject.getInteger(field.getName()));
method.setAccessible(true);
method.invoke(bean, jsonObject.getInteger(field.getName()));
} else {
//正常的处理
}
这里也是调用set方法的反射,通过调用set方法,把属性值放到类里,和基础类型方法设置一样,所以可以改成这样。这里只判断了Integer类型,其他类型需要额外加
if (typeClazz.isPrimitive()) {
setProperty(bean, field, jsonObject.get(field.getName()));
} else if (field.getGenericType().toString().equals(
"class java.lang.Integer")) {
setProperty(bean, field, jsonObject.get(field.getName()));
}
最终的代码,奉上:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Locale;
/**
* 通过类发射,用json设置属性
*/
public class TestInvoke {
@SuppressWarnings("rawtypes")
public static void main(String args[]) throws Exception {
String jsonStr = "{\n" +
" \"name\": \"name1\",\n" +
" \"age\": 30,\n" +
" \"sex\": true,\n" +
" \"child\": {\n" +
" \"sex\": 1\n" +
" }\n" +
"}";
JSONObject jsonObject = JSON.parseObject(jsonStr);
System.out.println(jsonObject.toJSONString());
People people = new People();
getFieldByClass(people, jsonObject);
System.out.println("======================================");
System.out.println("设置后的bean的值为:\n" + people.getName() + "\t" + people.getAge());
System.out.println(JSON.toJSON(people).toString());
}
/**
* 设置实例类的属性
*
* @param obj 要被赋值的实例类
* @param field 要被赋值的属性
* @param valueObj 要被赋值的属性的值
*/
private static void setProperty(Object obj, Field field, Object valueObj) {
try {
Class<?> clazz = obj.getClass();
//获取类的setXxx方法,xxx为属性
Method method = clazz.getDeclaredMethod(
"set"
+ field.getName().substring(0, 1)
.toUpperCase(Locale.getDefault())
+ field.getName().substring(1), field.getType());
//设置set方法可访问
method.setAccessible(true);
//调用set方法为类的实例赋值
method.invoke(obj, valueObj);
} catch (Exception e) {
e.printStackTrace();
}
}
static Object getFieldByClass(Object bean, JSONObject jsonObject)
throws Exception {
Class userCla = bean.getClass();
/*
* 得到类中的所有属性集合
*/
Field[] fs = userCla.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field field = fs[i];
field.setAccessible(true); // 设置些属性是可以访问的
Object val = field.get(bean);// 得到此属性的值
System.out.println("name:" + field.getName() + "\t value = " + val);
Class<?> typeClazz = field.getType();
if (typeClazz.isPrimitive()) {
setProperty(bean, field, jsonObject.get(field.getName()));
} else if (field.getGenericType().toString().equals(
"class java.lang.Integer")) {
setProperty(bean, field, jsonObject.get(field.getName()));
} else {
Object typeObj = typeClazz.newInstance();
if (typeObj instanceof String) {
System.out.println(field.getType() + "\t是String");
field.set(bean, jsonObject.getString(field.getName())); // 给属性设值
} else {
System.out.println(field.getType() + "\t");
field.set(bean, getFieldByClass(typeObj, jsonObject.getJSONObject(field.getName())));
}
}
}
return bean;
}
}
class People {
private String name;
private Integer age;
private boolean sex;//false是女,true是男
private Child child;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}
class Child {
private String sex;
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}