一、摘要

在实际开发过程中,经常碰到需要进行对象与map之间互转的问题,其实对于对象、Map 之间进行互转有很多种方式,下面我们一起来梳理一下:

  • 利用 JSON 工具包,将对象转成字符串,之后再转成 Map,这种需要转换2次,相对来说效率比较底;
  • 利用 Java 反射,获取 Bean 类的属性和值,再转换到 Map 对应的键值对中,相对来说这种方法效率高些,在实现上比较麻烦;
  • 利用 Java 的内省(Introspector) 实现,获取 Bean 类的属性和值,Map与对象互转,效率比较高;
  • 利用 apache 中的 BeanUtils工具包进行操作,底层实现类似方法三;
  • 利用net.sf.cglib.beans.BeanMap类中的方法,这种方式效率也非常高;

二、常用方法

也不多说了,直接show code,为了更接近实际场景,我们新建两个实体类UserRole,假设一个用户有多个角色,如下:

publicclass User {

    private String userId;

    private String userName;

    private List<Role> roleList;

    //... 省略 setter 和 getter

    public User() {}

    public User(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}
publicclass Role { private String userId; private String roleName; //... 省略 setter 和 getter public Role(String userId, String roleName) {
this.userId = userId;
this.roleName = roleName;
}
}

2.1、通过 JSON 进行转换

在这里,我们利用阿里巴巴的fastjson包进行转换,通过maven引入 jar,如下:

<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>

方法如下:

publicclass BeanMapUtilByJson {

    /**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
return JSONObject.parseObject(JSON.toJSONString(object),Map.class);
} /**
* map转对象
* @param map
* @param beanClass
* @param <T>
* @return
*/
publicstatic <T> T mapToBean(Map map, Class<T> beanClass){
return JSONObject.parseObject(JSON.toJSONString(map),beanClass);
}
}

2.2、利用反射进行转换

这种操作是利用 java 原生提供的反射特性来实现互转,方法如下:

publicclass BeanMapUtilByReflect {

    /**
* 对象转Map
* @param object
* @return
* @throws IllegalAccessException
*/
public static Map beanToMap(Object object) throws IllegalAccessException {
Map<String, Object> map = new HashMap<String, Object>();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
map.put(field.getName(), field.get(object));
}
return map;
} /**
* map转对象
* @param map
* @param beanClass
* @param <T>
* @return
* @throws Exception
*/
publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
T object = beanClass.newInstance();
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
int mod = field.getModifiers();
if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
field.setAccessible(true);
if (map.containsKey(field.getName())) {
field.set(object, map.get(field.getName()));
}
}
return object;
}
}

2.3、利用内省机制进行转换

内省(Introspector)是 Java 语言对 JavaBean 类属性、事件的一种缺省处理方法,也是基于 java 原生实现,操作如下:

publicclass BeanMapUtilByIntros {

    /**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object) throws Exception {
Map<String, Object> map = new HashMap<String, Object>();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor property : propertyDescriptors) {
String key = property.getName();
if (key.compareToIgnoreCase("class") == 0) {
continue;
}
Method getter = property.getReadMethod();
Object value = getter!=null ? getter.invoke(object) : null;
map.put(key, value);
}
return map;
} /**
* map转对象
* @param map
* @param beanClass
* @param <T>
* @return
* @throws Exception
*/
publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
T object = beanClass.newInstance();
BeanInfo beanInfo = Introspector.getBeanInfo(object.getClass());
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor property : propertyDescriptors) {
Method setter = property.getWriteMethod();
if (setter != null) {
setter.invoke(object, map.get(property.getName()));
}
}
return object;
}
}

2.4、利用 apache 中的 BeanUtils 进行转换

在使用这个方法前,需要手动引入 apache 中的 beanutils 包,方法如下:

<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>

想必大家都不会陌生,操作如下:

publicclass BeanMapUtilByApache {

    /**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
returnnew org.apache.commons.beanutils.BeanMap(object);
} /**
* map转对象
* @param map
* @param beanClass
* @param <T>
* @return
*/
publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
T object = beanClass.newInstance();
org.apache.commons.beanutils.BeanUtils.populate(object, map);
return object;
}
}

2.5、利用 cglib 中的 BeanMap 进行转换

在使用这个方法前,需要手动引入cglib 包,方法如下:

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

Spring 内置了 cglib,在项目中经常看到有同学用这个方法,操作如下:

publicclass BeanMapUtilByCglib {

    /**
* 对象转Map
* @param object
* @return
*/
public static Map beanToMap(Object object){
Map<String, Object> map = new HashMap<String, Object>();
if (object != null) {
BeanMap beanMap = BeanMap.create(object);
for (Object key : beanMap.keySet()) {
map.put(key+"", beanMap.get(key));
}
}
return map;
} /**
* map转对象
* @param map
* @param beanClass
* @param <T>
* @return
* @throws Exception
*/
publicstatic <T> T mapToBean(Map map, Class<T> beanClass) throws Exception {
T bean = beanClass.newInstance();
BeanMap beanMap = BeanMap.create(bean);
beanMap.putAll(map);
return bean;
}
}

2.6、测试

上面介绍完了操作,最后我们来测试一下,新建一个测试客户端TestClient,分别测试上面5个工具类

publicclass BeanMapClient {

    /**
* 测试
* @param args
*/
public static void main(String[] args) {
//为了更贴近实际场景,构造嵌套实体对象
User user = new User("1","张三");
List<Role> roleList = new ArrayList<Role>();
roleList.add(new Role("1","技术经理"));
roleList.add(new Role("1","信息主任"));
user.setRoleList(roleList);
//bean转map
Map userMap = BeanMapUtilByJson.beanToMap(user);
System.out.println("转换后的map:" + JSON.toJSONString(userMap));
//修改源对象中信息
user.getRoleList().get(0).setRoleName("项目经理");
user.getRoleList().add(new Role("1","项目经理"));
//map转bean
User newUser = BeanMapUtilByJson.mapToBean(userMap,User.class);
System.out.println("转换后的bean:" + JSON.toJSONString(newUser));
}
}

输出结果如下:

对上面5中输出结果进行分析,可以得出如下结论:

  • 将对象转换成map,基本都一致,将map转成bean的时候,有些小区别;
  • 方法一,通过json转换后的bean对象,即使源对象发生改变,转换后的对象不会发生变化,这是因为json在底层转换bean时,都创建了新的对象;
  • 方法二、三、四、五,当源对象有嵌套对象,修改嵌套对象,也就是Role内容,转换后的对象也会随之发生改变;

从结果可以看出,方法一、二、三、四、五,都可以进行对象与 map 的互转,那他们到底有啥区别呢?

下面我们从性能角度来观察一下,使用for循环测试 map 与对象的互转,结果如下:

可能每个机器的性能不一样,这个是我的电脑上测试的结果,从数据上可以看出:

  • 性能最好的是反射方法,其次就是内省方法,这两个方法都没有引用第三方jar包,所以相对可能要快点;
  • 使用第三方引用中,cglib 效率还可以,其次 apache的beanUtils工具包,最后就是Json包;

三、总结

如果对性能要求很高,可以采用 java 原生编程实现对象与 map 的互转,如果已经引用了 apache 或者 cglib 的jar,可以利用它提供的方法进行转换,优先推荐使用 cglib,因为 Spring 已经继承了 cglib,在项目中可以直接使用!

原文链接:https://mp.weixin.qq.com/s/6dq6aKfV1GKLOvD-RGmcpw

对象Bean与Map互转问题的更多相关文章

  1. bean 与 map 互转.

    package com.sprucetec.tms.distribute.utils;import java.beans.BeanInfo;import java.beans.Introspectio ...

  2. java的bean和map互转的工具类

    import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;i ...

  3. java 如何将实体bean和map互转化 (利用Introspector内省)

    // 将一个map对象转化为bean public static void transMap2Bean(Map<String, Object> map, Object obj) { try ...

  4. Java中把对象、对象bean、list集合、对象数组、Map和Set以及字符串转换成Json

    对象转换为Json 对象bean转换为Json List集合转换为Json 对象数组转换为Json Map集合转换为Json Set集合转为Json 字符串转换为Json 把Java对常用的一些数据转 ...

  5. java中 json和bean list map之间的互相转换总结

    JSON 与 对象 .集合 之间的转换 JSON字符串和java对象的互转[json-lib]   在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级 ...

  6. Dom4J解析xml文件动态转换为List<Bean>或者Map集合

    大家在解析大量相似xml文件的时候是否会遇到这样一个问题:冗余的代码去set定义的实体对象Bean的值,基本都是一样的操作   而且毫无任何代码价值可言所以在这写了一个简单的例子,类封装了几个方法你只 ...

  7. JAVA bean与XML互转的利器---XStream

    最近在项目中遇到了JAVA bean 和XML互转的需求, 本来准备循规蹈矩使用dom4j忽然想起来之前曾接触过的XStream, 一番研究豁然开朗,利器啊利器, 下来就XStream的一些用法与大家 ...

  8. Java对象转换成Map

    需求总是千奇百怪,对象转成map,看似没必要,但就是有这个需求,所以记录下来 首先是Bean package tools; import lombok.Data; /** * 车辆实体类 */ @Da ...

  9. Java bean 转 Map

    Java bean 转 Map 时需要使用Fastjson //方法 一 Map<String, Object> a = (Map<String, Object>)JSON.t ...

随机推荐

  1. redis学习三连奏,绝对让你彻底吃透分布式架构精髓

    2020年初,远程办公与直播授课成为国民刚需,腾讯因此免费开放可支持300人同时在线会议的“腾讯会议”.一时之间,这款软件的用户呈爆发性增长,据统计,腾讯会议一天就有近较100倍日常的会议数量. 谈及 ...

  2. UPAD for iCloud

    UPAD for iCloud笔记软件 在笔记软件中创建文件夹橡皮:按两下橡皮就是清除整个屏幕导出笔记到pdf,或者直接导出到其他应用中打开在当前页面中新建一个页面删除某个页面

  3. CentOS配置禁止root用户直接登录

    Linux的默认管理员名即是root,只需要知道ROOT密码即可直接登录SSH.禁止Root从SSH直接登录可以提高服务器安全性.经过以下操作后即可实现.本文适用于CentOS.Debian等Linu ...

  4. Docker Compose 启动mysql,redis,rabbitmq

    这里使用的centos7,首先切换到root. sudo -s 首先去设置下载镜像,否则下载这三个东西要很久,而且可能失败. vim /etc/docker/daemon.json 内容如下: { & ...

  5. burpsuite抓取小程序的数据包(指定DNS)

    目标:burpsuite抓取微信小程序的数据包,而且该系统需指定DNS!否则无法访问! 大家都知道小程序是https传输的,所以手机端是需要安装burp证书的. 已忽略安装证书的步骤,可自己百度搜索, ...

  6. Python3 基本语法 学习笔记

    如何定义python源文件的文件编码 如果想要定义文件代码的编码,一个特殊的注释应该放到源文件的第一或第二行,例如: # coding=<encoding name> 或 使用一种大多数编 ...

  7. JS函数深入

    函数的本质是对象 三种定义方式 1.  字面量=function声明 function add() { // body... } add(); 2.  var赋值表达式 var add = funct ...

  8. gitlab持续集成,自动部署

    写这篇文章的目的是,实现提交代码到gitlab上的一个项目时,自动打包,并将包发布到另一台服务器上,重启tomat.如有问题,可以联系本人QQ:409838567 gitlab-ci,是基于gitla ...

  9. 【整理】IC失效机理(持续更新)

    IC  四种常见失效机理如下: EM     -- electron migration,电子迁移)TDDB -- time dependent dielectric breakdown,与时间相关电 ...

  10. 如何调试TaskPaper的JavaScript上下文?

    Mac 上的纯文本 GTD 工具TaskPaper for Mac(纯文本任务管理器)是一款适用于Mac操作系统的软件.如何调试TaskPaper的JavaScript上下文?[dl]15-1068[ ...