浅谈java中的浅拷贝(浅复制)和深拷贝(深复制)

浅拷贝:
浅拷贝又称为浅复制,浅克隆,浅拷贝是指拷贝时只拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量的值都含有与原来对象相同的值,而所有对其他对象的引用都指向原来的对象,简单地说,浅拷贝只拷贝对象不拷贝引用。
深拷贝:
深拷贝又称为深复制,深克隆,深拷贝不仅拷贝对象本身,而且还拷贝对象包含的引用所指向的对象,拷贝出来的对象的所有变量(不包含那些引用其他对象的变量)的值都含有与原来对象的相同的值,那些引用其他对象的变量将指向新复制出来的新对象,而不指向原来的对象,简单地说,深拷贝不仅拷贝对象,而且还拷贝对象包含的引用所指向的对象。

再简单的说就是浅拷贝只拷贝对象,不拷贝引用。深拷贝对象引用全拷贝
java中常用的拷贝操作有三种:(1)操作符= (2)拷贝构造函数 (3)clone( )方法,由于java不支持运算符重载,所以我们不能在自己定义的类中定级操作符=操作。拷贝构造函数就不多说了,我们经常遇到。主要说一下clone方法,如果我们想要使自己定义的对象能够实现深拷贝,就需要改写从Object类中继承来的clone方法,clone方法在Object类中是protected权限,是为了防止意外的支持clone操作,所以我们需要把它改写成public权限的

看如下代码:

public class CloneTest{
    public static void main(String[] args) {
        People p = new People("xiaowang",10);
        Employee employee = new Employee("zhangsan", 20,p);
        Employee newEmployee = (Employee)employee.clone();
        newEmployee.p.name = "lisi";
        newEmployee.p.age = 30;
        System.out.println("employee.p.name="+employee.p.name+"
                 "+"employee.p.age="+employee.p.age);
        System.out.println("newEmployee.p.name="+newEmployee.p.name+"
                 "+"newEmployee.p.age="+newEmployee.p.age);
    }
}

class People
{
    String name;
    int age;
    People(String name,int age)
    {
        this.name = name;
        this.age = age;
    }
}
class Employee implements Cloneable
{
    String name;
    int age;
    People p;

    Employee(String name,int age,People p)
    {
        this.name = name;
        this.age = age;
        this.p = p;
    }

    public Object clone()
    {
        Employee obj = null;
        try
        {
            obj = (Employee)super.clone();  //Object中需要识别你要克隆的对象
        } catch (CloneNotSupportedException e) 
        {
            System.out.println(e.toString());
        }
        return obj;
    }
}

运行结果为:
employee.p.name=lisi employee.p.age=30
newEmployee.p.name=lisi newEmployee.p.age=30

上述代码如果运行以后,会改变原来对象的employee.p.name和”employee.p.age,因为这是浅拷贝,只是拷贝了对象,而引用还是以前对象的引用,所以更改了现在对象的引用元对象的引用也是会改变
再来看一下深拷贝

public class CloneTest {
    public static void main(String[] args) {
        People p = new People("xiaowang",10);
        Employee employee = new Employee("zhangsan", 20,p);
        Employee newEmployee = (Employee)employee.clone();
        newEmployee.p.name = "lisi";
        newEmployee.p.age = 30;
        System.out.println("employee.p.name="+employee.p.name+" "+"employee.p.age="+employee.p.age);
        System.out.println("newEmployee.p.name="+newEmployee.p.name+" "+"newEmployee.p.age="+newEmployee.p.age);
    }
}

class People implements Cloneable
{
    String name;
    int age;
    People(String name,int age)
    {
        this.name = name;
        this.age = age;
    }

    public Object clone()
    {
        Object obj = null;
        try
        {
            obj = super.clone();
        } catch (CloneNotSupportedException e) 
        {
            System.out.println(e.toString());
        }
        return obj;
    }
}

class Employee implements Cloneable
{
    String name;
    int age;
    People p;

    Employee(String name,int age,People p)
    {
        this.name = name;
        this.age = age;
        this.p = p;
    }

    public Object clone()
    {
        Employee obj = null;
        try
        {
            obj = (Employee)super.clone();  //Object中需要识别你要克隆的对象
        } catch (CloneNotSupportedException e) 
        {
            System.out.println(e.toString());
        }
        obj.p = (People)p.clone();
        return obj;
    }
}

运行结果为:
employee.p.name=xiaowang employee.p.age=10
newEmployee.p.name=lisi newEmployee.p.age=30

现在我们改进成了深拷贝,就会发现不会改变原来对象的employee.p.name和”employee.p.age,说明我们深拷贝拷贝了对象和对象的引用

java里面还有一种实现深拷贝的方法,就是运用对象的序列化机制,记得我是在java核心技术卷第九版卷二第一章看到的,很有趣。
序列化机制有一种很有趣的用法:提供了一种克隆对象的简便途径,只要对应的类是可序列化的就可以,做法是:直接将对象序列化到输出流中,然后将其读回,这样产生的新的对象是对现有对象的一个深拷贝。在此过程中,我们不必将对象写到文件中,因为可以用ByteArrayOutputStream将数据保存到字节数组中。
示例代码:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.GregorianCalendar;

public class SerialCloneTest {
    public static void main(String[] args)
    {
        Employee harry = new Employee("Harry Hacker",35000,1929,10,1);
        Employee harry2 = (Employee)harry.clone();
        harry.raiseSalary(10);
        System.out.println(harry);
        System.out.println(harry2);
    }
}
class SerialCloneable implements Cloneable,Serializable
{
    public Object clone()
    {
        try 
        {
            ByteArrayOutputStream bout = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bout);
            out.writeObject(this);
            out.close();

            ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
            ObjectInputStream in = new ObjectInputStream(bin);
            Object ret = in.readObject();
            in.close();
            return ret;
        } catch (Exception e)
        {
            return null;
        }
    }
}

class Employee extends SerialCloneable
{
    private String name;
    private double salary;
    private Date hireDay;

    public Employee(String n,double s,int year,int month,int day)
    {
        name = n;
        salary = s;
        GregorianCalendar calendar = new GregorianCalendar(year,month - 1,day);
        hireDay = calendar.getTime();
    }
    public String getName() {
        return name;
    }
    public double getSalary() {
        return salary;
    }
    public Date getHireDay() {
        return hireDay;
    }
    public void raiseSalary(double byPercent)
    {
        double raise = salary * byPercent / 100;
    }

    public String toString()
    {
        return getClass().getName()+"[name="+name+",salary="+salary+",hireDay="+hireDay+"]";
    }
}

上面的示例代码是自己照着书敲得,敲一遍也明白了点,不过我们应该当心用这种方法,尽管它很灵巧,但是它通常会比显示的构建新的对象并复制或克隆数据域的克隆方法慢很多

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java拷贝(Deep Copy)和拷贝(Shallow Copy)是用于复制对象的两种不同方式。 拷贝是指创建一个新对象,然后将原始对象的非静态字段的值复制到新对象。如果字段是基本数据类型,则复制其值;如果字段是引用类型,则复制引用而不是实际对象。这意味着新旧对象将共享同一个引用对象。当修改其一个对象的引用对象时,另一个对象也会受到影响。 拷贝是指创建一个新对象,并将原始对象的所有字段的值复制到新对象,包括引用类型字段。这意味着新对象将拥有原始对象的副本,而不是共享引用。即使修改其一个对象的引用对象,另一个对象也不会受到影响。 Java提供了几种方式实现拷贝拷贝: 1. 对于拷贝,可以使用`clone()`方法。该方法是Object类的一个protected方法,需要在要拷贝的类实现Cloneable接口,并重写`clone()`方法。然后通过调用`clone()`方法来创建拷贝对象。 2. 对于拷贝,可以使用序列化和反序列化来实现。将对象写入输出流,然后再从输入流读取对象,可以得到一个全新的拷贝对象。 需要注意的是,如果原始对象包含引用类型的字段,那么引用类型对象也需要实现Cloneable接口并重写`clone()`方法,或者是可序列化的。否则,在进行拷贝拷贝时,引用类型对象仍然会被共享或不被复制。 希望能解决你的问题!如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值