厦门网站seo外包,榆林做网站多少钱,营销推广计划书,建设部网站从哪登陆关于Spring中的BeanUtils的使用的细节和由此导致的巨坑
前言
本文研究关于spring带的BeanUtils的坑。
即 BeanUtils.copyProperties 的使用注意点
结论#xff1a;
字段名字要相同#xff08;完全相同包括大小写#xff0c;其实应该是set-get方法名#xff09;类型要相…关于Spring中的BeanUtils的使用的细节和由此导致的巨坑
前言
本文研究关于spring带的BeanUtils的坑。
即 BeanUtils.copyProperties 的使用注意点
结论
字段名字要相同完全相同包括大小写其实应该是set-get方法名类型要相同primitive type和对应包装类同Source必须有getter且必须publicTarget必须有setter且必须publicSource中的static字段则不行例如static和static final的都不行Target中final的字段不会被赋值例如Target中的final和static final字段Source或Target中若有父类父类中的字段是可以复制的Source中内嵌的非普通类型的字段需要注意 避免大坑 1只是把Source中的引用给到TargetTarget中改变会导致两边都变化 2ListA 和 ListB 转换是OK的只是把引用交给了后者要注意遍历的时候会发生类型转换异常 这里说的 “非普通类型” 可以理解为除了 8种原始类型primitive type8中原始类型对应的包装类String类之外的的引用类型 其实还要注意下如果有继承的情况下会发生什么事情其实不会有大的问题见后面继承的字段也把它当做当前类的字段即可得到结论
使用注意点 假设有个Source类和一个Target类 Source转换到Target一般除了基础类型的字段这里说的 “基础类型” 是指8种原始类型、对应的包装类、String类型如果包含有其他类型的使用要十分谨慎!!!
Source里的字段名和Target里的字段名必须完全一样这个能够转换的第一个条件Source里的字段类型和Target里的要严格相同这是第二个条件 Integer 类型转 Integer 是ok的int - Integer (ok原始类型和包装类是互通的)Integer - int (ok)int - long (not ok同是整数仅范围不同不行必须严格相同类型)int - Long (not ok)long - int (not ok)long - Integer (not ok)Dog - Dog (ok)Animal - Animal (ok)Dog - Animal (not ok即使是Dog继承Animal不行必须严格相同的类型)Animal - Dog (not ok)ListA - ListB (ok非常大的坑极其容易在后续使用时发生ClassCastException参考后续的附录中的代码) Source里需要被拷贝的字段需要有getterTarget的字段需要有setter第三个条件Source里需要被拷贝的字段的getter和Target里的setter都只能是public的protected/private/不写即default通通不行第四个条件Source里的字段不能是static的含static final第五条件Target里的字段不能是final的含static final第六条件
注意
BeanUtils是浅拷贝不是深拷贝只是把引用弄过去 例如Source中有A类的字段fieldTarget中也有A类的字段field则Source中的field和Target中的field将会是相同的对象哈希码相同 如果Source中有非普通字段谨慎用BeanUtils最好将内嵌的转换后再set到外层不然很多坑!!!
2. Source里的父类的字段也能被拷贝
举例
注意无特别表示都表示Source有getterTarget有getter且都是public的
SourceTarget是否可以拷贝字段名age字段名age2否字段类型int字段类型int是字段类型int字段类型Integer是字段类型Integer字段类型int是字段类型int字段类型Long否字段类型int字段类型long否字段类型Long字段类型int否字段类型boolean字段类型boolean是字段类型boolean字段类型Boolean是字段类型Boolean字段类型boolean是字段类型Dog继承Animal字段类型Animal否字段类型ListA字段类型ListB是。虽然有泛型但能赋值过去但存在严重隐患见附录字段类型Boolean字段类型Boolean是Source继承Super1Super1里有name字段Target继承Super2Super2里也有name字段是Source继承Super1Super1里有name字段Target里有name字段不继承是Source有name字段不继承Target继承Super2Super2里有name字段是字段修饰static如static Integer age任意修饰符如static/static final/普通类型/final否。不抛异常但读取不了Source的static字段字段修饰普通字段任意修饰符如static/普通类型(除final/static final)是但不能set到Target是final的字段修饰final任意修饰符如static/普通类型(除final/static final)是但不能set到Target是final的
Source中的serialVersionUID就是Serializable要求的那个字段会出现什么情况? 会覆盖Target中的吗? 好像不会吧这个final的不会转过去因为是static的
附录
下面演示了一个巨大的坑
public class Test_A_Fucking_Problem {public static void main(String[] args) {Source source new Source();Pet p1 new Pet();p1.setName(dog);Pet p2 new Pet();p2.setName(cat);ListPet petList new ArrayList();petList.add(p1);petList.add(p2);source.setPetList(petList);Target target new Target();BeanUtils.copyProperties(source, target);System.out.println(target: target ,target.petList.hashCode: (target.getPetList() null ? 未被赋值: target.getPetList().hashCode()) ,petList.hashCode: petList.hashCode());// ★★需要非常注意的点Source是ListA 但是Target是ListBBeanUtils是可以把值赋值到target的因为都是List类型它不会管泛型不同的// 但是赋值过去实际上是把对象的引用引过去也就是 ListB petList 字段其实是被赋值了 ListA petList 的实例在下面运行的过程就出现类转换异常// get(0) 还不会出现异常但是get(0)后再getName则JVM需要弄清楚这个get(0)得到是什么类型当发现类型跟声明的泛型类型不一样的时候就抛出了运行时异常ClassCast...)System.out.println(target.getPetList().get(0));System.out.println(target.getPetList().get(0).getName());}
}public class Source {private ListPet petList;public ListPet getPetList() {return petList;}public void setPetList(ListPet petList) {this.petList petList;}
}public class Target {private ListPet2 petList;public ListPet2 getPetList() {return petList;}public void setPetList(ListPet2 petList) {this.petList petList;}
}public class Pet {private String name;public String getName() {return name;}public void setName(String name) {this.name name;}
}public class Pet2 {private String name;public String getName() {return name;}public void setName(String name) {this.name name;}
}