当前位置: 首页 > article >正文

Spring在不同类型之间也能相互拷贝?

场景还原

日常开发中,我们会定义非常多的实体,例如VO、DTO等,在涉及实体类的相互转换时,常使用Spring提供的BeanUtils.copyProperties,该类虽好,可不能贪用。

这不在使用过程中就遇到一个大坑,分析原来如此,我们定义伪代码如下:

    @Setter
    @Getter
    static class Father {

        private List<Son> childrenList;
    }

    @Setter
    @Getter
    @ToString
    static class Mother {
        private List<Daughter> childrenList;
    }

    @Setter
    @Getter
    static class Son {

        private String name;

        private Integer age;
    }

    @Setter
    @Getter
    static class Daughter {

        private String name;

        private Integer age;
    }

我们定义了一家四口,老爸带儿子们,老妈带女儿们,我们运行如下伪代码:

public static void main(String[] args) {
        Father father = new Father();
        List<Son> childrenList = new ArrayList<Son>();
        Son son = new Son();
        son.setName("xiaoming");
        son.setAge(28);
        childrenList.add(son);
        father.setChildrenList(childrenList);
        Mother mother = new Mother();
        System.out.println("copy before:" + JSON.toJSONString(mother));
        BeanUtils.copyProperties(father, mother);
        System.out.println("copy after:" + JSON.toJSONString(mother));
    }

插播一则通告:本人在代码一线工作近八年时间,有非常丰富的面试经验,有需要优化简历,模拟面试的同学可以联系V:xiaolang1530368931。将简历优化成大厂面试官想看的,提前回答大厂面试官可能会问的问题,为进大厂做最后的冲刺。

大家猜下运行的结果是什么?老爸有没有成功甩手将儿子们扔给老妈?从定义上看,老爸和老妈的字段属性名称都是叫childrenList,但是泛型类型不一样,按照平常的用法,类型不一致,是没有办法进行拷贝的,但是我们运行后发现结果如下:

copy before:{}
copy after:{"childrenList":[{"age":28,"name":"xiaoming"}]}

奇怪,按道理前后应该都是空才对,这为什么成功拷贝了?

问题分析

不知道各位同学刚才有没有注意,我特别把泛型类型给飘红了,它确实是类型不一致,但更准确的说是泛型类型不一致。

这里就有一个非常重要的基础知识:

泛型只存在于编译阶段,运行时泛型信息会被擦除!

也就是我们的List<Son>和List<Daughter>全部都会被擦除为List<Object>,那两个List<Object>,属性名称一样不就能拷贝成功么!

而且非常奇特的是我们看下如下截图:

我们会发现Mother的原本定义的Daughter类型竟然变成Son类型了。从这个例子中切切时时感受到了泛型擦除。

看到这里,有些同学会问那这不是有bug吗,我的类型都被替换了。这点Java语言在设计泛型的时候就已经考虑了。虽然运行泛型被擦除了,但是当你使用的时候依然是你定义的具体类型,以上面这个例子,我们运行如下伪代码:

public static void main(String[] args) {
        Father father = new Father();
        List<Son> childrenList = new ArrayList<Son>();
        Son son = new Son();
        son.setName("xiaoming");
        son.setAge(28);
        childrenList.add(son);
        father.setChildrenList(childrenList);
        Mother mother = new Mother();
        System.out.println("copy before:" + JSON.toJSONString(mother));
        BeanUtils.copyProperties(father, mother);
        List<Daughter> daughterList = mother.getChildrenList();
        for (int i = 0; i < daughterList.size(); i++) {
            Daughter daughter = daughterList.get(i);
            System.out.println(daughter.getName());
        }
        System.out.println("copy after:" + JSON.toJSONString(mother));
    }

我们会发现copy after:并没有输出,输出结果如下:

copy before:{}
Exception in thread "main" java.lang.ClassCastException: com.github.TestClass$Son cannot be cast to com.github.TestClass$Daughter
	at com.github.TestClass.main(TestClass.java:32)

会发现虽然绕过了编译,但是使用的时候报类型转换异常。

总结

因为Java语言泛型的特性,目前Spring并没有提供重载方法来规避这个问题,但实际上这个问题也无需规避,本身运行起来类型一致就可以直接拷贝,只不过后续如果我们遇到此问题应该了解其根因。

分享一句非常喜欢的话:把根牢牢扎深,再等春风一来,便会春暖花开。

PS:以上引用信息以及图片均来自网络公开信息,如有侵权,请留言或联系

504401503@qq.com,立马删除。


http://www.kler.cn/a/322290.html

相关文章:

  • D3中颜色的表示方法大全
  • 【WPF】Prism学习(八)
  • Cyberchef使用功能之-多种压缩/解压缩操作对比
  • Proteus 8.17的详细安装教程
  • 独立开发:一人公司模式下副业产品的全流程
  • 任务管理功能拆解——如何高效管理项目任务?
  • 【java17】java17新特性之Stream.toList()
  • 3271.哈希分割子串
  • 前端使用vue点击上传文件,传送给后端,后端进行文件接收
  • 区块链—共享块存储安全可信任可追踪分布式数据库系统技术
  • LTE SSS产生过程中z序列的介绍和MATLAB以及C语言实现
  • 7个不为人知的实用软件推荐
  • 关于VSCode里需要用的一些插件总结
  • 19 基于51单片机的倒计时音乐播放系统设计
  • USB 3.1 标准 A 型到 USB 3.1 标准 A 型或 B 型的电缆组件
  • Spring MVC 基础 : 文件、cookies的接收 ,REST响应
  • python命令行怎么换行
  • Python批量处理客户明细表格数据,挖掘更大价值
  • 电脑退域或切换系统账号后系统黑屏
  • C#基于SkiaSharp实现印章管理(8)
  • 这五本大模型书籍,让你从大模型零基础到精通,非常详细收藏我这一篇就够了
  • 【PyTorch】环境配置
  • MySQL 数据转换技巧:列转行与行转列
  • Redis支持数据类型,它们各自的应用场景是
  • 基于以太坊+IPFS的数据交易平台进行效率评估
  • MapReduce学习与理解