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

Java中克隆对象后修改仍影响原对象?如何实现无影响掩码

克隆对象修改后影响原对象的原因及解决方法

为什么克隆后修改新对象会影响原对象?

你当前使用的super.clone()是浅克隆:

  • 对于基本数据类型(如int、long)以及不可变类型(如String),会直接复制值;
  • 对于自定义引用类型字段(比如requestBody、RequestHeader),只会复制对象的引用地址,不会复制引用指向的实际对象实例。

也就是说,原request和克隆出的requestMasking,它们的requestBody字段指向的是同一个RequestBody实例,PersonalData也是同一个实例。当你调用requestMasking.getRequestBody().getPersonalData().setIdCard(...)时,本质是修改了这个共享的PersonalData对象的身份证字段,所以原request的身份证信息也会被同步修改。

你的UnderwriteRequest类的clone方法仅直接调用super.clone(),没有对引用类型字段做深复制处理,这就是问题的核心原因。

如何实现无影响的数据掩码?

需要实现深克隆,确保原对象和克隆对象的所有嵌套引用类型字段都是独立的实例。下面提供两种实用方案:

方案1:手动实现深克隆

让所有嵌套的引用类型类都实现Cloneable接口,重写clone方法,然后在UnderwriteRequest的clone方法中手动克隆每个引用字段。

示例修改:

  1. 让嵌套类实现Cloneable并实现深克隆:
@Getter
@Setter
public class RequestBody implements Cloneable {
    private PersonalData personalData;
    // 其他字段...

    @Override
    public Object clone() throws CloneNotSupportedException {
        RequestBody cloned = (RequestBody) super.clone();
        // 克隆PersonalData实例
        if (this.personalData != null) {
            cloned.personalData = (PersonalData) this.personalData.clone();
        }
        return cloned;
    }
}

@Getter
@Setter
public class PersonalData implements Cloneable {
    private String idCard;
    // 其他字段...

    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone(); // 字段均为不可变类型,浅克隆足够
    }
}
  1. 修改UnderwriteRequest的clone方法,克隆所有引用字段:
@Getter
@Setter
public class UnderwriteRequest implements Cloneable{
    private RequestHeader requestHeader;
    private RequestBrmsBody requestBrmsBody;
    private RequestBody requestBody;
    private RESPONSE_STATUS status = RESPONSE_STATUS.FAILED;
    private String message;

    @Override
    public Object clone() throws CloneNotSupportedException {
        UnderwriteRequest cloned = (UnderwriteRequest) super.clone();
        // 逐个克隆引用类型字段
        if (this.requestHeader != null) {
            cloned.requestHeader = (RequestHeader) this.requestHeader.clone();
        }
        if (this.requestBrmsBody != null) {
            cloned.requestBrmsBody = (RequestBrmsBody) this.requestBrmsBody.clone();
        }
        if (this.requestBody != null) {
            cloned.requestBody = (RequestBody) this.requestBody.clone();
        }
        return cloned;
    }
}

修改后,克隆出的requestMasking与原request的所有嵌套对象都是独立实例,修改克隆对象的身份证不会影响原对象。

方案2:序列化/反序列化实现深克隆

如果嵌套类层级多、数量多,手动编写clone方法效率低,可以用序列化方式:将对象序列化为字节流再反序列化,得到完全独立的新对象。

示例代码(基于Jackson):

import com.fasterxml.jackson.databind.ObjectMapper;

// 深克隆工具方法
public static UnderwriteRequest deepClone(UnderwriteRequest original) throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    String jsonStr = mapper.writeValueAsString(original);
    return mapper.readValue(jsonStr, UnderwriteRequest.class);
}

修改maskingData方法,替换原克隆逻辑:

public static UnderwriteRequest maskingData(UnderwriteRequest request) {
    try {
        UnderwriteRequest requestMasking = deepClone(request);
        if(request != null 
           && request.getRequestBody() != null 
           && request.getRequestBody().getPersonalData() != null
           && !request.getRequestBody().getPersonalData().getIdCard().isEmpty()) {
            maskIdCard(requestMasking);
        }
        return requestMasking;
    }catch (Exception e) {
         log.error("掩码处理失败", e);
         return request; // 或根据业务返回默认值
    }
}

// 简化maskIdCard方法,无需传入原request
public static void maskIdCard(UnderwriteRequest requestMasking) {
    String maskChar = "X";
    String maskString = StringUtils.repeat(maskChar, 9);
    String idcard = requestMasking.getRequestBody().getPersonalData().getIdCard();
    requestMasking.getRequestBody().getPersonalData().setIdCard(StringUtils.overlay(idcard, maskString, 0, 9));
}

这种方式不需要每个类都实现Cloneable,只要是普通POJO(无特殊序列化限制)即可使用,更高效便捷。

额外优化建议

  • 移除maskIdCard方法中原request参数,直接从克隆对象获取数据,避免误操作原对象;
  • 异常日志改用log.error输出,便于问题排查;
  • 可使用Optional或自定义工具类简化多层空指针判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 19:43:20