在写需求时遇到了个bug,关于这个方法的用法产生了点疑问,不知道算是深拷贝还是浅拷贝。自己写了个类
- src和target无子对象
@Data
public class T1 {
private String name;
private List<String> values;
}
@Data
public class T2 {
private String name;
private List<String> values;
}
List<String> s1 = new ArrayList<>();
List<String> s2 = new ArrayList<>();
s1.add("11");
s1.add("22");
s2.add("op");
T1 t1 = new T1();
t1.setValues(s1);
t1.setName("t1");
T2 t2 = new T2();
BeanUtils.copyProperties(t1,t2);
System.out.println(t2.getValues());
t1.setValues(s2);
System.out.println(t2.getValues());
如果是拷贝的引用,那么两次输出的应该不一样,但是结果是两次输出都一样。 这种情况和我遇到的bug不太一样,我就又试了如果是子对象的情况。
- src和target有子对象集合
@Data
public class T1 {
private String name;
private List<Son1> values;
}
@Data
public class T2 {
private String name;
private List<Son2> values;
}
@Data
public class Son1 {
private String age;
private String sex;
}
@Data
public class Son2 {
private String age;
private String sex;
}
List<Son1> s1 = new ArrayList<>();
List<Son1> s2 = new ArrayList<>();
Son1 son1 = new Son1();
son1.setAge("18");
son1.setSex("male");
s1.add(son1);
T1 t1 = new T1();
t1.setValues(s1);
t1.setName("t1");
T2 t2 = new T2();
BeanUtils.copyProperties(t1,t2);
System.out.println(t2.getValues());
t1.setValues(s2);
System.out.println(t2.getValues());
此时,神奇的事情来了,如果赋值的两个类的属性名一样,但是种类不同,他还是会把source的种类复制到target上。看一下调试结果: 明明T2这个类的values属性应该是List<Son2> ,但是现在却变成了List<Son1> !!!
再玩的花一点,把T2的属性改为其它类,T1的属性不变:
@Data
public class T2 {
private String name;
private List<OrderVO> values;
}
List<Son1> s1 = new ArrayList<>();
List<Son1> s2 = new ArrayList<>();
Son1 son1 = new Son1();
son1.setAge("18");
son1.setSex("male");
s1.add(son1);
T1 t1 = new T1();
t1.setValues(s1);
t1.setName("t1");
T2 t2 = new T2();
BeanUtils.copyProperties(t1,t2);
System.out.println(t2.getValues());
List<OrderVO> t2Values = t2.getValues();
t1.setValues(s2);
System.out.println(t2.getValues());
System.out.println(t2Values.get(0).getFee());
更神奇的事情又来了,虽然T2的values属性是List<OrderVO> 了。但是BeanUtils方法运行完毕赋值的还是List<Son1> …
看这一行代码List<OrderVO> t2Values = t2.getValues(); 居然不报错能执行成功,但是当执行到真的从list中取对象的时候System.out.println(t2Values.get(0).getFee()); 就会报错,错误是java.lang.ClassCastException。。。害人不浅啊! 个人觉得是运行时类型不匹配不会报错,编译时检查你的写法没问题,所以代码可以运行,但是真的取数据时才会报错。
- src和target只有子对象
如果values属性不是集合,而是单纯的子对象,那么就不会复制成功。
@Data
public class T1 {
private String name;
private Son1 values;
}
@Data
public class T2 {
private String name;
private OrderVO values;
}
运行结果如下:
Tips: 1.BeanUtils.copyProperties确实是深拷贝,list类型不是复制的引用,原有list改变不会影响复制后的; 2.如果拷贝的属性是子对象的集合,那么需要确保src和target的子对象是同一个类,否则就自己再写一遍BeanUtils.copyProperties来拷贝子对象。 3.如果拷贝的对象的属性只是个子对象,而且target和src的子对象不是同一个,那么即便属性名相同也不会复制,target中相关属性只会是null。
个人猜测为什么子对象集合不行,可能判断是否能复制是根据属性名和类型来的,对于List中的每个对象,可能jvm都当成了一个类似于json的东西,只判断了都是集合,没有去判断集合里的对象是不是同一个。
|