最近发现了一个现象: 用 BeanUtils.copyProperties(Object source, Object target) 时, 如果 source 和 target 中有 List 对象, 然后修改了 source 的 List 对象中的元素, 发现 target 的 List 对象也会跟着变化.
调研了 BeanUtils.copyProperties(Object source, Object target) 源码, 发现是通过 method.invoke 方法来实现属性的 copy 的, 所以对象的属性复制都是浅 Copy.
于是乎就换了一个种方式来写:
- List<A> source = new ArrayList<>();
- source.add(new A());
- List<A> copy = new ArrayList<>(source);
发现居然还是不行!
觉得很奇怪, 然后看了 ArrayList 的构造方法,
- public ArrayList(Collection<? extends E> c) {
- elementData = c.toArray();
- if ((size = elementData.length) != 0) {
- // c.toArray might (incorrectly) not return Object[] (see 6260652)
- if (elementData.getClass() != Object[].class)
- elementData = Arrays.copyOf(elementData, size, Object[].class);
- } else {
- // replace with empty array.
- this.elementData = EMPTY_ELEMENTDATA;
- }
- }
elementData = c.toArray() 这段代码还是浅 Copy.
思考了一会, 难道只能通过遍历元素, 然后添加元素的方式来解决吗? 抱着疑问去 Google 了下, 发现该函数 Collections.copy 解决了问题, 进入其源码发现是在遍历元素然后再添加...
总结
copy 完之后, 一般都是直接返回给调用方了, 一般不会再次操作数据, 这样就不会引发浅 Copy 的问题. 这也是 copy 的正确用法.
来源: https://juejin.im/post/5bee8ddde51d454eee66dd02