BeanUtil.copyProperties(source,target)拷贝List注意事项

一:抛出问题

java 复制代码
import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String id;
    private String name;
    /* 用于存储用户的订单 */
    private List<Order> orders;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
  public static class Order{
      /* 订单ID */
      private String orderId;
      /* 订单名称 */
      private String orderName;
   }

    /**
     * BeanUtil.copyProperties(source,target)方法拷贝List类型数据时。对target对象中的List数据修改会影响到source对象中的List数据
     */
    public static void main(String[] args) {
        User source = new User();
             source.setId("001");
             source.setName("001号用户");

        // 构建source对象orders数据
        List<Order> orders = new ArrayList();
        Order order = new Order();
              order.setOrderId("1");
              order.setOrderName("1号订单");
        orders.add(order);
        source.setOrders(orders);
        System.out.println("source = " + source); // 输出:User(id=001, name=001号用户, orders=[User.Order(orderId=1, orderName=1号订单)])

        // 构建拷贝对象
        User target = new User();

        // 属性拷贝
        BeanUtil.copyProperties(source,target);
        System.out.println("target = " + target); // 输出:User(id=001, name=001号用户, orders=[User.Order(orderId=1, orderName=1号订单)])

        // 对target对象中的orders集合数据进行修改,观察source对象中的orders集合数据是否会发送变化
        Order targetOrder = target.getOrders().get(0);
              targetOrder.setOrderId("2");
              targetOrder.setOrderName("2号订单");

         // 输出target对象
        System.out.println("target = " + target); // User(id=001, name=001号用户, orders=[User.Order(orderId=2, orderName=2号订单)])

        /**
         * 输出source对象
         *      发现source对象中的orders数据被修改了。原因在于对于List类型使用BeanUtil.copyProperties(source,target)方法重source拷贝数据到target时。target对象中的orders对象其实是source对象中orders对象的引用(本质上是同一个对象)
         *      所以出现了对target对象中List类型的orders对象数据修改同时也会影响到source对象中的List类型的orders数据。
         */
        System.out.println("source = " + source); // User(id=001, name=001号用户, orders=[User.Order(orderId=2, orderName=2号订单)])
    }
}

二:解决方式

已知上面对target对象中的List数据修改时会影响到source对象中的List数据;也清楚了出现这个问题的原因在于使用copyProperties方法拷贝List属性时只是将source中List的引用拷贝给target中的List(source和target对象中的List本质上为同一个对象);

java 复制代码
import cn.hutool.core.bean.BeanUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String id;
    private String name;
    /* 用于存储用户的订单 */
    private List<Order> orders;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
  public static class Order{
      /* 订单ID */
      private String orderId;
      /* 订单名称 */
      private String orderName;
   }


    public static void main(String[] args) {
        User source = new User();
             source.setId("001");
             source.setName("001号用户");

        // 构建source对象orders数据
        List<Order> orders = new ArrayList();
        Order order = new Order();
              order.setOrderId("1");
              order.setOrderName("1号订单");
        orders.add(order);
        source.setOrders(orders);
        System.out.println("source = " + source); // 输出:User(id=001, name=001号用户, orders=[User.Order(orderId=1, orderName=1号订单)])

        // 构建拷贝对象
        User target = new User();

        // 属性拷贝
        BeanUtil.copyProperties(source,target);

        // 解决方式:使用copyToList拷贝List数据时会创建一个新的List而不是地址值引用(将创建出来新的List对象赋值给target中的List)
        List<Order> newOrders = BeanUtil.copyToList(source.getOrders(), Order.class);
        target.setOrders(newOrders);
        System.out.println("target = " + target); // 输出:User(id=001, name=001号用户, orders=[User.Order(orderId=1, orderName=1号订单)])

        // 对target对象中的orders集合数据进行修改,观察source对象中的orders集合数据是否会发送变化(不会)
        Order targetOrder = target.getOrders().get(0);
              targetOrder.setOrderId("2");
              targetOrder.setOrderName("2号订单");

         // 输出target对象
        System.out.println("target = " + target); // User(id=001, name=001号用户, orders=[User.Order(orderId=2, orderName=2号订单)])

        // 输出source对象
        System.out.println("source = " + source); // User(id=001, name=001号用户, orders=[User.Order(orderId=1, orderName=1号订单)])
    }
}
相关推荐
律宏阔38 分钟前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔38 分钟前
Windows 禁用联想笔记本所有 Lenovo 后台服务
windows
律宏阔38 分钟前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴39 分钟前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千1 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei371 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei371 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei371 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
GeW1 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
GeW1 小时前
工业场景中的Linux与数据库选型:高端化转型的技术底座
linux