@Data @AllArgsConstructor @NoArgsConstructor public class Address { private String province; private String city; } @Data @AllArgsConstructor @NoArgsConstructor public class Order { // 堆代码 duidaima.com //订单ID private String orderId; //收货地址 private Address shippingAddress; }我们写一段代码测试一下:
public class Test { public static void main(String[] args) { Address oldAddress = new Address("广东", "湛江"); Order oldOrder = new Order("666", oldAddress); Order newOrder = new Order(); BeanUtils.copyProperties(oldOrder, newOrder); System.out.println(oldOrder.getShippingAddress() == newOrder.getShippingAddress()); oldOrder.getShippingAddress().setCity("深圳"); System.out.println(JSON.toJSONString(oldOrder)); System.out.println(JSON.toJSONString(newOrder)); } } //输出 true {"orderId":"666","shippingAddress":{"city":"深圳","province":"广东"}} {"orderId":"666","shippingAddress":{"city":"深圳","province":"广东"}}可以发现,使用了BeanUtils.copyProperties之后呢,新订单和老订单对象的地址属性,指向同一个引用,也就是说,BeanUtils.copyProperties是浅拷贝。当我们对oldOrder的shippingAddress修改时,newOrder的shippingAddress也会同时被修改。我们日常开发的时候,经常使用BeanUtils.copyProperties,这时候尤其要注意,这个浅拷贝的坑,要不然某个引用属性被莫名奇妙修改了都不知道。
.MapStruct深拷贝写法
@Data @AllArgsConstructor @NoArgsConstructor public class Order { private String orderId; private Address shippingAddress; public Order deepCopy() { //深拷贝、新new一个地址对象出来 Address newAddress = new Address(this.shippingAddress.getProvince(), this.shippingAddress.getCity()); return new Order(this.orderId, newAddress); } }再次验证一下:
public static void main(String[] args) { Address oldAddress = new Address("广东", "湛江"); Order oldOrder = new Order("666", oldAddress); Order newOrder = oldOrder.deepCopy(); System.out.println(oldOrder.getShippingAddress() == newOrder.getShippingAddress()); oldOrder.getShippingAddress().setCity("深圳"); System.out.println(JSON.toJSONString(oldOrder)); System.out.println(JSON.toJSONString(newOrder)); } //输出 false {"orderId":"666","shippingAddress":{"city":"深圳","province":"广东"}} {"orderId":"666","shippingAddress":{"city":"湛江","province":"广东"}}3.2 实现Cloneable接口,重写clone()
@Data @AllArgsConstructor @NoArgsConstructor public class Address implements Cloneable{ private String province; private String city; //重写clone @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } @Data @AllArgsConstructor @NoArgsConstructor public class Order implements Cloneable { private String orderId; private Address shippingAddress; //重写clone @Override protected Object clone() throws CloneNotSupportedException { Order newOrder = (Order)super.clone(); newOrder.setShippingAddress((Address)shippingAddress.clone()); return newOrder; } }3.3 序列化实现深拷贝
@Data @AllArgsConstructor @NoArgsConstructor public class Order implements Serializable { private String orderId; private Address shippingAddress; public Order deepCopy(Order order) { //序列化实现深拷贝 return SerializationUtils.clone(order); } }但是,SerializationUtils.clone相对于其他,性能方面不是很理想,大家可以自己去验证一下看看哈。
@Mapper public interface AddressMapper { Address deepCopy(Address address); } @Mapper(uses = {AddressMapper.class}) public interface OrderMapper { OrderMapper INSTANCE = Mappers.getMapper(OrderMapper.class); @Mapping(target = "shippingAddress", source = "order.shippingAddress") Order deepCopy(Order order); } @Data @AllArgsConstructor @NoArgsConstructor public class Order implements Serializable { private String orderId; private Address shippingAddress; //MapStruct写法的深拷贝 public Order deepCopy() { OrderMapper mapper = OrderMapper.INSTANCE; return mapper.deepCopy(this); } }