You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中对象复制后如何实现对象隔离?

解决BeanUtils拷贝后对象引用不隔离的问题

你遇到的这个问题本质是浅拷贝导致的。BeanUtils.copyProperties默认只做浅拷贝:对于基本数据类型(比如String、int这些),它会复制值;但对于像C这样的引用类型,它只是把a里AttC的内存地址复制给了b的AttC——也就是说,a.AttC和b.AttC指向同一个对象实例。所以你修改a.setAttC(null)时,b的AttC自然也变成了null,因为它们本来就是同一个东西。

要实现两个对象完全隔离,你需要做深拷贝:不仅复制基本类型的属性,还要为所有引用类型的属性创建新的实例,复制它们的内部属性。下面是几种可行的方案:

1. 手动实现深拷贝方法

这是最直观的方式,针对你的引用类型(比如C类)写一个拷贝方法,然后在复制对象时手动处理引用属性:

// 先给C类添加一个拷贝方法,复制自身的所有属性
public class C {
    private String name;

    // getter和setter省略
    public C copy() {
        C newC = new C();
        newC.setName(this.name);
        // 如果C还有其他引用类型属性,也要递归调用它们的copy方法
        return newC;
    }
}

// 复制a到b的逻辑
A a = new A();
C c = new C();
c.setName("c name");
a.setAtt1("toto");
a.setAtt2("toto");
a.setAttC(c);

B b = new B();
// 先用BeanUtils拷贝基本类型属性
BeanUtils.copyProperties(a, b);
// 手动深拷贝C类型的属性
if (a.getAttC() != null) {
    b.setAttC(a.getAttC().copy());
}

// 现在修改a的AttC,不会影响b了
a.setAttC(null);
System.out.println(b.getAttC().getName()); // 输出"c name"

2. 通过序列化实现通用深拷贝

如果你的所有类(A、B、C)都实现了Serializable接口,可以用序列化+反序列化的方式生成一个完全独立的对象,这种方式不需要手动写每个类的拷贝方法:

import java.io.*;

public class DeepCopyUtil {
    @SuppressWarnings("unchecked")
    public static <T> T deepCopy(T obj) throws IOException, ClassNotFoundException {
        if (obj == null) return null;
        
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.close();
        
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        T copiedObj = (T) ois.readObject();
        ois.close();
        
        return copiedObj;
    }
}

// 使用示例
B b = new B();
BeanUtils.copyProperties(a, b);
// 替换AttC为深拷贝后的实例
b.setAttC(DeepCopyUtil.deepCopy(a.getAttC()));

3. 使用第三方库实现深拷贝

如果不想自己写代码,可以用成熟的第三方库来处理,比如:

  • MapStruct:编译期生成映射代码,性能高,支持深拷贝,只需要定义映射接口即可
  • Apache Commons Lang:SerializationUtils.clone()方法,基于序列化实现深拷贝
  • ModelMapper:支持自动映射和深拷贝配置

以MapStruct为例,步骤如下:

  1. 引入MapStruct依赖(Maven/Gradle)
  2. 定义映射接口:
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;

@Mapper
public interface AToBMapper {
    AToBMapper INSTANCE = Mappers.getMapper(AToBMapper.class);
    
    // MapStruct会自动处理基本类型和引用类型的深拷贝(只要C类的属性可以直接映射)
    B convert(A a);
}
  1. 使用映射器:
B b = AToBMapper.INSTANCE.convert(a);
// 修改a的AttC不会影响b
a.setAttC(null);
System.out.println(b.getAttC().getName()); // 输出"c name"

核心思路就是:让a和b的引用类型属性指向不同的对象实例,而不是同一个内存地址,这样修改其中一个就不会影响另一个了。

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:07:15