map和object相互转换的几种方法和对比

工作中经常遇到这样的场景,需要在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)

你可以先记住这个结论,继续往下看。

第二种方法,利用commons.BeanUtils

示例代码如下:

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比反射好用,它里面做了大量的转换工作,反射的方法更多需要你自己来处理。

第三种方法,json转换

这里使用 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最耗时。当然这个不是官方结论,只是我自己本地环境测试的结果。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中提供了一个将MapObject的示例代码。这段代码首先创建了一个Map对象,并向其中添加了一些键值对。然后通过遍历Map的forEach方法,将每个键值对添加到一个新创建的Object对象中。最后返回这个新创建的Object对象。通过运行这段代码,可以得到一个包含Map中所有键值对的Object对象。\[1\] 另外,引用\[2\]和引用\[3\]中也提供了一些关于Map转换Object的测试方法的示例代码,但是这些代码是使用Java语言编写的,与引用\[1\]中的JavaScript代码不同。因此,如果你想在JavaScript中将MapObject,可以参考引用\[1\]中的示例代码。 #### 引用[.reference_title] - *1* [map结构object结构](https://blog.csdn.net/weixin_43191327/article/details/123059840)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [mapobject相互转换几种方法和对比](https://blog.csdn.net/pony_maggie/article/details/102938727)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值