博客
关于我
学习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/

你可能感兴趣的文章
Python制作进度条,原来有这么多方法
查看>>
Python制作简单的学生成绩管理系统
查看>>
python制作甘特图的基本知识(附Demo)
查看>>
python制作一个简单的服务器,【Python】 做一个简单的 http 服务器
查看>>
Python到底能做什么?它的优点在哪?
查看>>
python利用pytorch库导出图像分割算子
查看>>
python利用pyshark监听网卡来抓包其中pyshark中摸索的一些可用参数
查看>>
python利用excel分析过杀漏失
查看>>
python判断汉字数目
查看>>
python判断文件是空的,如果是空的,就删除
查看>>
python判断密码是否正确_python密码判断是否符合要求的方法
查看>>
python判断字符串包含中文_Python 判断字符串是否包含中文
查看>>
python删除第一行_Python 乱码指北:一行删掉根目录
查看>>
Python删除列表元素的三种方法
查看>>
python初步学习-python数据类型-集合(set)
查看>>
python列表生成字典_Python中将字典转换为列表的方法
查看>>
python列表对应元素合并为列表及判断一个列表是几维
查看>>
python+flask计算机毕业设计骨科门诊患者档案管理系统(程序+开题+论文)
查看>>
python+flask计算机毕业设计高校体测管理系统的设计与实现(程序+开题+论文)
查看>>
python+flask计算机毕业设计高校体育赛事系统(程序+开题+论文)
查看>>