object堆内存地址是全新
的;对象的各个属性值 prop Value
,也是全新的,指向全新的堆内存地址。method 参数传递的是内存地址
,也就是对象的引用句柄,只有 primitive 基本类型和String 作为参数时,传递的才是值spring / apache commons
等工具类的 BeanUtils.copy
方法 ❌类似 java 的对象序列化和反序列化过程( object Serialization & deserialization ),产生的是全新的对象
不同的是,java 对象序列化需要落地为磁盘文件,jackson 序列化则正常运行在jvm内存中。
Jackson 是个神奇的东东,共有3种方式可实现深拷贝,来源
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.util.TokenBuffer;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.List;
@Slf4j
@Component
public class JacksonUtils {
@Autowired
ObjectMapper objectMapper;
private static JacksonUtils MAPPER;
/**
* 非 Controller 层使用 @Autowired 方式注入 spring 初始化好的全局单例 objectMapper
* 无需自己手动 new ObjectMapper();
*/
@PostConstruct
public void init(){
MAPPER = this; // JacksonUtils 类的单例 bean
MAPPER.objectMapper = this.objectMapper; // spring启动过程中,会暴露该 objectMapper 单例
}
}
/**
* 不同class类型拷贝
* @Param clazz 这个类,必须有1个默认的构造 方法,这是使用 Jackson 正反序列化必须的;
* 如果是Gson 进行正反序列化,则没有该 构造方法 的要求 :
* Gson 参考 https://www.baeldung.com/java-deep-copy#2-json-serialization-with-gson
*/
@SneakyThrows
public static <T> T deepClone(Object javaObj, Class<T> clazz) {
ObjectMapper mapper = MAPPER.objectMapper;
// method 1 : json string 🚗 . 速度最慢,但是兼容性较好
if(javaObj instanceof String){
return mapper.readValue(mapper.writeValueAsString(javaObj), targetClass);
}
// method 2 : jsonNode tree 🛫
// return mapper.treeToValue(mapper.valueToTree(javaObj), clazz);
// method 3 : token buffer 🚀
TokenBuffer tb = new TokenBuffer(mapper, false);
mapper.writeValue(tb, javaObj);
return mapper.readValue(tb.asParser(), clazz);
}
/**
* 相同class类型拷贝
*/
@SneakyThrows
public static <T> T deepClone(T source) {
return (T) deepClone(source, source.getClass());
}