Java 对象深拷贝

需求

写一个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转为一个新的对象。

使用 googleGSON 序列化和反序列化代码如下:

// 对象 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);

// ================ Gson 对集合数据的处理,如 List<User>  ================
List<User> users = new ArrayList<User>();
users.add(new User());
users.add(new User());
String usersStr = gson.toJson(users);
// 使用 TypeToken 对集合等非单一包装对象处理
List<TagEntry> usersCopy= gson.fromJson(usersStr ,  new TypeToken<List<User>>(){}.getType());

另一种常用序列化拷贝是借助于 commons-lang 工具包下的 org.apache.commons.lang.SerializationUtils 类,代码如下

// User 必须实现 Serializable
User a = new User();
User b = (User)SerializationUtils.clone(a);

注: 采用 SerializationUtils 工具序列化拷贝的对象必须实现 Serializable 接口。

总结

以上介绍了浅拷贝和深拷贝的概念,并且介绍了两种常用的深拷贝方法。当然,也可以自己实现深拷贝,比如通过反射实现,或者通过重写 clone 方法实现等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的对象拷贝有两种方式:浅拷贝和深拷贝。 浅拷贝是指创建一个新对象,新对象中的引用类型字段仍然指向原对象中对应字段的引用。这意味着修改新对象中的引用类型字段也会影响原对象。可以通过实现 Cloneable 接口并重写 clone() 方法来实现浅拷贝。 示例代码如下: ```java class MyClass implements Cloneable { private int value; private MyObject myObject; public MyClass(int value, MyObject myObject) { this.value = value; this.myObject = myObject; } // 重写 clone() 方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class MyObject { // ... } public class Main { public static void main(String[] args) throws CloneNotSupportedException { MyObject obj = new MyObject(); MyClass obj1 = new MyClass(10, obj); // 浅拷贝 MyClass obj2 = (MyClass) obj1.clone(); // obj1 和 obj2 是两个独立的对象,但是它们的 myObject 字段引用同一个对象 System.out.println(obj1 == obj2); // false System.out.println(obj1.myObject == obj2.myObject); // true } } ``` 深拷贝是指创建一个新对象,同时递归地复制原对象及其引用类型字段所引用的对象。这样在修改新对象时不会影响原对象。可以通过实现 Serializable 接口并使用序列化/反序列化来实现深拷贝。 示例代码如下: ```java import java.io.*; class MyClass implements Serializable { private int value; private MyObject myObject; public MyClass(int value, MyObject myObject) { this.value = value; this.myObject = myObject; } // 深拷贝 public MyClass deepClone() throws IOException, ClassNotFoundException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(this); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); return (MyClass) objectInputStream.readObject(); } } class MyObject implements Serializable { // ... } public class Main { public static void main(String[] args) throws IOException, ClassNotFoundException { MyObject obj = new MyObject(); MyClass obj1 = new MyClass(10, obj); // 深拷贝 MyClass obj2 = obj1.deepClone(); // obj1 和 obj2 是两个独立的对象,它们的 myObject 字段引用不同的对象 System.out.println(obj1 == obj2); // false System.out.println(obj1.myObject == obj2.myObject); // false } } ``` 上述代码中,通过使用序列化/反序列化实现了深拷贝。在 `deepClone()` 方法中,首先将对象写入字节数组输出流,然后通过字节数组输入流读取字节数组并反序列化为一个新的对象。这样就能够得到一个与原对象完全独立的新对象,包括其引用类型字段所引用的对象

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值