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方法中手动克隆每个引用字段。
示例修改:
- 让嵌套类实现
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(); // 字段均为不可变类型,浅克隆足够 } }
- 修改
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
相关产品推荐
相关产品推荐

