需求
写一个java对象深拷贝工具,用以对象深拷贝。
分析
在 Java 中,变量间值的传递分为两种。对于 int,char,string,等基本数据类型进行值传递时,使用值传递。即原变量 a 的值与新变量 b 的值相等,且 a 与 b 拥有不同的内存地址;对于非基本数据类型的变量进行传值时使用引用传值。即原变量 a 与新变量 b 的值相同(因为他们都指向相同的内存地址),且 a 与 b 拥有相同的内存地址。
基本数据类型传值示意
int a = 10;
int b = a;
如下图,当执行 int a = 10;
时,JVM 会先对变量 a 分配内存 0x0001 , 并在其中存储数据 10。当执行 int b = a;
时,JVM 也会为变量 b 分配一块内存 0x0011 ,并在其中存储 10。
引用数据类型传值示意
User a = new User();
User b = a;
// 或 方法传值
User a = new User();
addUser(a);
private void addUser(User b){
// …… 业务省略
}
如下图,当执行 User a = new User();
时,JVM 会分配一块内存,其中存储着对象 User
的初始化信息,紧接着,JVM 将该内存的地址 0x0001 分配给变量 a
;当程序执行到 User b = a;
或 addUser(a);
时,
浅拷贝
对基本数据类型进行值传递,对引用数据类型进行引用传递的拷贝,为浅拷贝。
深拷贝
对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,为深拷贝。
综上,浅拷贝与深拷贝的差异在于对引用对象的拷贝,如果是的引用类型的数据拷贝与基本数据类型的拷贝达到相同的效果(除了值相同外,其他所有都不相同)则认为完成了数据深拷贝。
实现
- 序列化拷贝
先将对象序列化,然后再反序列化为一个新的对象。最简单的序列化拷贝方法是结合JSON,先将对象转为JSON,再将JSON转为一个新的对象。
使用 google
的 GSON
序列化和反序列化代码如下:
// 对象 a
User a = new User();
// 创建 Gson 实例
Gson gson = new Gson();
// 序列化为 json 字符串
String jsonStr = gson.toJson(a);
// 反序列化 json 字符串为 对象 b
User b = gson.fromJson(jsonStr,User.class);
另一种常用序列化拷贝是借助于 commons-lang
工具包下的 org.apache.commons.lang.SerializationUtils
类,代码如下
// User 必须实现 Serializable
User a = new User();
User b = (User)SerializationUtils.clone(a);
注: 采用 SerializationUtils
工具序列化拷贝的对象必须实现 Serializable
接口。
总结
以上介绍了浅拷贝和深拷贝的概念,并且介绍了两种常用的深拷贝方法。当然,也可以自己实现深拷贝,比如通过反射实现,或者通过重写 clone 方法实现等。