工作中经常遇到这样的场景,需要在object和map直接相互转换,这里总结一下。
我先定义一个实体类,后面介绍的几种转换方法都以这个实体类为例进行说明。
public class PersonBean { private String name; //姓名 private Integer age; //年龄 private Boolean boy; //是否男孩 private Date birthday; //生日 }
这里尽量覆盖不同的属性类型,便于全面的测试转换方法。
然后我们写个测试方法验证一下,
@Test public void test1() throws Exception { Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "fcbox"); map.put("age", 15); map.put("boy", true); map.put("birthday", new Date()); PersonBean person = (PersonBean)map2Object_1(map, PersonBean.class); System.out.println("方法1 map->object的转换结果:" + person); Map<String, Object> newMap = Object2Map_1(person); System.out.println("方法1 object->map的转换结果:" + JSON.toJSONString(newMap)); }
输出,
方法1 map->object的转换结果:PersonBean(name=fcbox, age=15, boy=true, birthday=Wed Nov 06 14:52:57 CST 2019) 方法1 object->map的转换结果:{"birthday":1573023177881,"name":"fcbox","boy":true,"age":15}
然后我们接着做个测试,把
map.put("boy", true);
改成
map.put("boy", "true");
会报异常,
java.lang.IllegalArgumentException: Can not set java.lang.Boolean field com.pony.app.PersonBean.boy to java.lang.String at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81) at java.lang.reflect.Field.set(Field.java:758) at com.pony.test.Map2ObjectTest.map2Object_1(Map2ObjectTest.java:66) at com.pony.test.Map2ObjectTest.test1(Map2ObjectTest.java:33) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:483) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) 方法1 map->object的转换结果:PersonBean(name=fcbox, age=15, boy=null)
你可以先记住这个结论,继续往下看。
示例代码如下:
public static Object map2Object_2(Map<String, Object> map, Class<?> clazz) { if (map == null) { return null; } Object obj = null; try { obj = clazz.newInstance(); //这个方法会遍历map<key, value>中的key,如果bean中有这个属性,就把这个key对应的value值赋给bean的属性。 BeanUtils.populate(obj, map); } catch (Exception e) { e.printStackTrace(); } return obj; } public static Map<?, ?> Object2Map_2(Object object) { if (object == null) { return null; } return new BeanMap(object); }
测试方法,
@Test public void teste2(){ Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "tom"); map.put("age", 15); map.put("boy", true); map.put("birthday", new Date()); PersonBean person = (PersonBean)map2Object_2(map, PersonBean.class); System.out.println("方法2 map->object的转换结果:" + person); Map<?, ?> newMap = Object2Map_2(person); System.out.println("方法2 object->map的转换结果:" + JSON.toJSONString(newMap)); }
输出,
方法2 map->object的转换结果:PersonBean(name=tom, age=15, boy=true, birthday=Wed Nov 06 14:53:47 CST 2019) 方法2 object->map的转换结果:{"birthday":1573023227193,"name":"tom","boy":true,"class":"com.pony.app.PersonBean","age":15}
然后像上个示例一样,把
map.put("boy", true);
改成
map.put("boy", "true");
你会发现依然可以正确的输出同样的结果。
从这点来看,beanutils比反射好用,它里面做了大量的转换工作,反射的方法更多需要你自己来处理。
这里使用 fastjson,其实用其它的组件也是可以的。
public static Object map2Object_3(Map<String, Object> map, Class<?> clazz) { if (map == null) { return null; } return JSON.parseObject(JSON.toJSONString(map), clazz); } public static Map<?, ?> Object2Map_3(Object object) { if (object == null) { return null; } return JSON.parseObject(JSON.toJSONString(object), Map.class); }
测试方法,
@Test public void test3(){ Map<String, Object> map = new HashMap<String, Object>(); map.put("name", "tom"); map.put("age", 15); map.put("boy", true); map.put("birthday", new Date()); PersonBean person = (PersonBean)map2Object_3(map, PersonBean.class); System.out.println("方法3 map->object的转换结果:" + person); Map<?, ?> newMap = Object2Map_3(person); System.out.println("方法3 object->map的转换结果:" + JSON.toJSONString(newMap)); }
输出,
方法3 map->object的转换结果:PersonBean(name=tom, age=15, boy=true, birthday=Wed Nov 06 15:30:47 CST 2019) 方法3 object->map的转换结果:{"birthday":1573025447719,"name":"tom","boy":true,"age":15}
json的方法似乎也不错,它的原理是先把map转成json,然后把json转成object。而且你可以测试下,它也是可以识别 map.put("boy", "true");
这种赋值方式的。
我在上面三个测试方法上增加耗时打印,发现三个方法的性能排名是:
方法1 > 方法3 > 方法2
也就是说,方法2最耗时。当然这个不是官方结论,只是我自己本地环境测试的结果。
欢迎关注我的公众号
(转载本站文章请注明作者和出处 思无邪了吗 )