对象Bean与Map互转问题

摘要:
=空?吸气剂。invoke(object):null;地图put(键,值);}returnmap;}/***映射传输对象*@parammap*@parambeanClass*@param*@return*@throwsException*/publicstaticTmapToBean(Mapmap,Cla

一、摘要

在实际开发过程中,经常碰到需要进行对象与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));
    }
}

输出结果如下:

对象Bean与Map互转问题第1张

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

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

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

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

对象Bean与Map互转问题第2张

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

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

三、总结

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

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

免责声明:文章转载自《对象Bean与Map互转问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇关于Ubuntu18.04 linux系统使用安装JDK Mysqljavabean与map互转下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C#编程总结(十三)数据压缩

C#编程总结(十三)数据压缩 在进行文件存储或者数据传输时,为了节省空间流量,需要对数据或文件进行压缩。在这里我们讲述通过C#实现数据压缩。 一、GZipStream压缩 微软提供用于压缩和解压缩流的方法。 此类表示 GZip 数据格式,它使用无损压缩和解压缩文件的行业标准算法。 这种格式包括一个检测数据损坏的循环冗余校验值。 GZip 数据格式使用的算法...

google Guava包的reflection(反射)解析

译者:万天慧(武祖) 由于类型擦除,你不能够在运行时传递泛型类对象——你可能想强制转换它们,并假装这些对象是有泛型的,但实际上它们没有。 举个例子: ArrayList<String> stringList = Lists.newArrayList(); ArrayList<Integer> intList = Lists.newA...

golang json解析

前言 Go 语言自带的 encode/json 包提供了对 JSON 数据格式的编码和解码能力。 解析 JSON 的关键,其实在于如何声明存放解析后数据的变量的类型。 此外使用 json 编码还会有几个需要注意的地方,谨防踩坑。 解析简单JSON 先观察下这段 JSON 数据的组成,name,created 是字符串。id 是整型,fruit 是一个字符串...

淘宝对接(二)

完成淘宝对接(一)的内容后,我们获得非常重要的App Key及App Secret。但如果想访问商户数据(如商品、订单等)还需要获取访问商户数据的授权令牌 Access Token。获取用户授权的流程可以查看淘宝文档:用户授权介绍。 尽管用户授权文档比较详尽地说明了申请流程。但在这里我还是挑出一些我当时不太明白的步骤进行讲解: 1. 获取授权码(即在"用户...

将json文件转换成insert语句的sql文件

引入是要的maven依赖: 1 <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> 2 <dependency> 3 <groupId>com.google.code.gson</groupId> 4 &l...

多线程知识点总结(一)

第一章  Java多线程技能   1、实现多线程的方式:一种是继承Thread类,另外一种是实现Runnable接口。       这两者的区别是:继承Thread类的本质是多个线程分别完成自己的任务,实现Runnable接口的本质是多个线程共同完成一个任务。 举例如下: 继承Thread类的,我们相当于拿出三件事即三个卖票10张的任务分别分给三个窗口,他...