博客
关于我
学习Java的深拷贝和浅拷贝
阅读量:307 次
发布时间:2019-03-03

本文共 4311 字,大约阅读时间需要 14 分钟。

Java 中的浅拷贝与深拷贝

在Java编程中,深拷贝和浅拷贝是非常重要的概念,了解它们的区别和实现方式,可以帮助我们更好地理解Java对象的传递机制。以下是关于浅拷贝和深拷贝的详细解释。

1. 创建对象的5种方式

1.1 通过 new 关键字

这是最常用的方式,通过调用类的构造方法创建对象。

Object obj = new Object();

1.2 通过 Class 的 newInstance() 方法

调用类的无参构造方法创建对象。

Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

1.3 通过 Constructor 类的 newInstance 方法

通过反射调用指定的构造方法创建对象。

Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

1.4 使用 Clone 方法

通过对象的 clone() 方法创建内容相同的对象。

Person p4 = (Person) p3.clone();

1.5 反序列化

将对象序列化为字节流,然后反序列化为新对象。

// 深度拷贝Object deepCopy = new Object() {    @Override    public Object clone() throws CloneNotSupportedException {        return super.clone();    }};

2. Clone 方法

2.1 Object 类中的 clone 方法

protected native Object clone() throws CloneNotSupportedException;

这是一个 native 方法,由Java虚拟机实现,用于创建对象的浅拷贝。

2.2 浅拷贝的特点

  • 对于基本类型字段,复制数值。
  • 对于引用类型字段,复制引用地址。

2.3 浅拷贝示例

@Testpublic void testShallowClone() throws Exception {    Person p1 = new Person("zhangsan", 21);    p1.setAddress("湖北省", "武汉市");    Person p2 = (Person) p1.clone();    System.out.println("p1: " + p1);    System.out.println("p2: " + p2);    p2.setAddress("湖北省", "荆州市");    System.out.println("p1地址变化: " + p1.getAddress());}

输出结果显示,修改 p2 的地址后,p1 的地址也随之改变,这是浅拷贝的特点。

3. 基本类型与引用类型

3.1 基本类型

  • char, boolean, byte, short, int, long, float, double
  • 直接存储在栈中。

3.2 引用类型

  • 包括类、接口、数组、枚举等。
  • 引用地址存储在栈中,实际数据存储在堆中。

3.3 示例

String c = new String("abc");String d = c;// c 和 d 引用同一个 String 对象。

4. 浅拷贝

4.1 浅拷贝机制

  • 创建新对象。
  • 复制当前对象的非静态字段。
  • 对于基本类型字段,直接复制数值。
  • 对于引用类型字段,复制引用地址。

4.2 浅拷贝示例

public class Person implements Cloneable {    private String pname;    private int page;    private Address address;    public Person(String pname, int page) {        this.pname = pname;        this.page = page;        this.address = new Address();    }    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

4.3 浅拷贝后的行为

Person p1 = new Person("zhangsan", 21);p1.setAddress("湖北省", "武汉市");Person p2 = p1.clone();// p2 的 address 引用与 p1 的 address 引用相同。

5. 深拷贝

5.1 深拷贝的目标

确保每个对象的所有引用对象也复制到新对象中,形成完全独立的对象。

5.2 深拷贝实现方法

5.2.1 重写克隆方法

public class Address implements Cloneable {    private String provices;    private String city;    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();    }}

5.2.2 序列化与反序列化

public Object deepClone() throws Exception {    ByteArrayOutputStream bos = new ByteArrayOutputStream();    ObjectOutputStream oos = new ObjectOutputStream(bos);    oos.writeObject(this);    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());    ObjectInputStream ois = new ObjectInputStream(bis);    return ois.readObject();}

5.3 深拷贝示例

@Testpublic void testDeepClone() throws Exception {    Person p1 = new Person("zhangsan", 21);    p1.setAddress(new Address("湖北省", "武汉市"));    Person p2 = p1.deepClone();    System.out.println("p1地址: " + p1.getAddress());    System.out.println("p2地址: " + p2.getAddress());}

输出结果显示,p1 和 p2 的地址不同,说明深拷贝成功。

6. 深拷贝的实现思路

6.1 自定义克隆方法

重写每个引用类型的 clone 方法,确保深拷贝。

public class Address implements Cloneable {    @Override    protected Object clone() throws CloneNotSupportedException {        Address addressClone = (Address) super.clone();        addressClone.provinces = new String(addressClone.provinces);        addressClone.city = new String(addressClone.city);        return addressClone;    }}

6.2 序列化方法

确保所有字段都被序列化。

public class Person implements Serializable {    private String pname;    private int page;    private Address address;    private static final long serialVersionUID = 1234567890L;    public Person(String pname, int page) {        this.pname = pname;        this.page = page;        this.address = new Address();    }    public Object deepClone() throws Exception {        ByteArrayOutputStream bos = new ByteArrayOutputStream();        ObjectOutputStream oos = new ObjectOutputStream(bos);        oos.writeObject(this);        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());        ObjectInputStream ois = new ObjectInputStream(bis);        return ois.readObject();    }}

6.3 第三方工具

使用工具如 Apache Commons 的 BeanUtils 或 Google Guava 的 Objects 类进行深拷贝。

总结

  • 浅拷贝:创建对象的内容,引用类型共享内存。
  • 深拷贝:创建对象的内容和引用对象的内容,保持完全独立。
  • 实现方法:自定义克隆方法、序列化反序列化或使用工具类。

理解这两种拷贝方式,能够帮助开发者在设计和维护Java程序时,正确选择适用的拷贝策略,提升程序的稳定性和可维护性。

转载地址:http://pngl.baihongyu.com/

你可能感兴趣的文章
MySQL 深度分页性能急剧下降,该如何优化?
查看>>
MySQL 深度分页性能急剧下降,该如何优化?
查看>>
MySQL 添加列,修改列,删除列
查看>>
mysql 添加索引
查看>>
MySQL 添加索引,删除索引及其用法
查看>>
mysql 状态检查,备份,修复
查看>>
MySQL 用 limit 为什么会影响性能?
查看>>
MySQL 用 limit 为什么会影响性能?有什么优化方案?
查看>>
MySQL 用户权限管理:授权、撤销、密码更新和用户删除(图文解析)
查看>>
mysql 用户管理和权限设置
查看>>
MySQL 的 varchar 水真的太深了!
查看>>
mysql 的GROUP_CONCAT函数的使用(group_by 如何显示分组之前的数据)
查看>>
MySQL 的instr函数
查看>>
MySQL 的mysql_secure_installation安全脚本执行过程介绍
查看>>
MySQL 的Rename Table语句
查看>>
MySQL 的全局锁、表锁和行锁
查看>>
mysql 的存储引擎介绍
查看>>
MySQL 的存储引擎有哪些?为什么常用InnoDB?
查看>>
Mysql 知识回顾总结-索引
查看>>
Mysql 笔记
查看>>