Java的浅拷贝和深拷贝

 

浅拷贝:把一个对象中所有的非static成员变量(包括对其它对象的引用,java中的引用相当于C/C++中的指针变量)都拷贝一遍,而不拷贝引用所指向的对象

深拷贝:把一个对象中所有的非static成员变量(包括对其它对象的引用)都拷贝一遍,引用所指向的对象也拷贝一份

一个类的对象如果想要具有拷贝的功能,比如符合如下条件:

   1.必须实现Cloneable接口(这个接口中没有定义方法,叫做标记接口)

   2.重写Object类的clone()方法,该方法实现的是浅拷贝

   3.在该类的clone()方法中的第一句,比如调用super.clone()来调用Object的clone()方法来实现拷贝

浅拷贝的例子:

public class CloneTest  
{  
    public static void main(String[] args)  
    {  
        Student s1 = new Student();  
        s1.setAge(20);  
        s1.setName("wudi");  
        School school = new School();  
        school.setName("Peiyang University");  
        school.setBornYear(1895);  
        s1.setSchool(school);  
        System.out  
                .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                        + s1.getSchool().getName() + " " 
                        + s1.getSchool().getBornYear());  
          
        try 
        {  
            //拷贝一个学生  
            Student s2 = (Student)s1.clone();  
            s2.setAge(21);  
            s2.setName("WUDI");  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());  
              
            System.out.println("after s2 changing some property:");  
            //通过学生s2改变了他所在学校的名称和成立时间  
            s2.getSchool().setName("Tianjin University");  
            s2.getSchool().setBornYear(1951);  
              
              
            System.out  
            .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                    + s1.getSchool().getName() + " " 
                    + s1.getSchool().getBornYear());  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());   
               
}   
        catch (CloneNotSupportedException e)  
        {  
            e.printStackTrace();  
        }  
    }  
}  
class School  
{  
    private String name;  
    private int bornYear;  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }  
    public int getBornYear()  
    {  
        return bornYear;  
    }  
    public void setBornYear(int bornYear)  
    {  
        this.bornYear = bornYear;  
    }  
}  
class Student implements Cloneable  
{  
    private int age;  
    private String name;  
    private School school;  
    public School getSchool()  
    {  
        return school;  
    }  
    public void setSchool(School school)  
    {  
        this.school = school;  
    }  
    public int getAge()  
    {  
        return age;  
    }  
    public void setAge(int age)  
    {  
        this.age = age;  
    }  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }  
    @Override 
    protected Object clone() throws CloneNotSupportedException  
    {  
        return super.clone();  
    }  
}  
package com.test;
public class CloneTest
{
 public static void main(String[] args)
 {
  Student s1 = new Student();
  s1.setAge(20);
  s1.setName("wudi");
  School school = new School();
  school.setName("Peiyang University");
  school.setBornYear(1895);
  s1.setSchool(school);
  System.out
    .println("s1:" + s1.getName() + " " + s1.getAge() + " "
      + s1.getSchool().getName() + " "
      + s1.getSchool().getBornYear());
  
  try
  {
   //拷贝一个学生
   Student s2 = (Student)s1.clone();
   s2.setAge(21);
   s2.setName("WUDI");
   System.out
   .println("s2:" + s2.getName() + " " + s2.getAge() + " "
     + s2.getSchool().getName() + " "
     + s2.getSchool().getBornYear());
   
   System.out.println("after s2 changing some property:");
   //通过学生s2改变了他所在学校的名称和成立时间
   s2.getSchool().setName("Tianjin University");
   s2.getSchool().setBornYear(1951);
      
   System.out
   .println("s1:" + s1.getName() + " " + s1.getAge() + " "
     + s1.getSchool().getName() + " "
     + s1.getSchool().getBornYear());
   System.out
   .println("s2:" + s2.getName() + " " + s2.getAge() + " "
     + s2.getSchool().getName() + " "
     + s2.getSchool().getBornYear());
   
}
  catch (CloneNotSupportedException e)
  {
   e.printStackTrace();
  }
 }
}
class School
{
 private String name;
 private int bornYear;
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 public int getBornYear()
 {
  return bornYear;
 }
 public void setBornYear(int bornYear)
 {
  this.bornYear = bornYear;
 }
}
class Student implements Cloneable
{
 private int age;
 private String name;
 private School school;
 public School getSchool()
 {
  return school;
 }
 public void setSchool(School school)
 {
  this.school = school;
 }
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 @Override
 protected Object clone() throws CloneNotSupportedException
 {
  return super.clone();
 }

从运行结果可以看出,通过学生s2将其引用school所指向的对象的name和bornYear属性改变,相应的s1的也被改变,这说明学生s1和学生s2里面的school引用指向的始终是同一个School对象。这就是浅拷贝的含义。

深拷贝的例子:

public class CloneTest  
{  
    public static void main(String[] args)  
    {  
        Student s1 = new Student();  
        s1.setAge(20);  
        s1.setName("wudi");  
        School school = new School();  
        school.setName("Peiyang University");  
        school.setBornYear(1895);  
        s1.setSchool(school);  
        System.out  
                .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                        + s1.getSchool().getName() + " " 
                        + s1.getSchool().getBornYear());  
          
        try 
        {  
            //拷贝一个学生  
            Student s2 = (Student)s1.clone();  
            s2.setAge(21);  
            s2.setName("WUDI");  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());  
              
            System.out.println("after s2 changing some property:");  
            //通过学生s2改变了他所在学校的名称和成立时间  
            s2.getSchool().setName("Tianjin University");  
            s2.getSchool().setBornYear(1951);  
              
              
            System.out  
            .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                    + s1.getSchool().getName() + " " 
                    + s1.getSchool().getBornYear());  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());   
}   
        catch (CloneNotSupportedException e)  
        {  
            e.printStackTrace();  
        }  
    }  
}  
class School implements Cloneable  
{  
    private String name;  
    private int bornYear;  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }  
    public int getBornYear()  
    {  
        return bornYear;  
    }  
    public void setBornYear(int bornYear)  
    {  
        this.bornYear = bornYear;  
    }  
      
    @Override 
    protected Object clone() throws CloneNotSupportedException  
    {  
        return super.clone();  
    }  
}  
class Student implements Cloneable  
{  
    private int age;  
    private String name;  
    private School school;  
    public School getSchool()  
    {  
        return school;  
    }  
    public void setSchool(School school)  
    {  
        this.school = school;  
    }  
    public int getAge()  
    {  
        return age;  
    }  
    public void setAge(int age)  
    {  
        this.age = age;  
    }  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }  
    @Override 
    protected Object clone() throws CloneNotSupportedException  
    {  
        Student s2 = (Student)super.clone();  
          
        //将school所引用的对象也拷贝一份,并且让学生s2去引用这个新的School对象  
        s2.setSchool((School)school.clone());  
          
        return s2;  
    }  

package com.test;
public class CloneTest
{
 public static void main(String[] args)
 {
  Student s1 = new Student();
  s1.setAge(20);
  s1.setName("wudi");
  School school = new School();
  school.setName("Peiyang University");
  school.setBornYear(1895);
  s1.setSchool(school);
  System.out
    .println("s1:" + s1.getName() + " " + s1.getAge() + " "
      + s1.getSchool().getName() + " "
      + s1.getSchool().getBornYear());
  
  try
  {
   //拷贝一个学生
   Student s2 = (Student)s1.clone();
   s2.setAge(21);
   s2.setName("WUDI");
   System.out
   .println("s2:" + s2.getName() + " " + s2.getAge() + " "
     + s2.getSchool().getName() + " "
     + s2.getSchool().getBornYear());
   
   System.out.println("after s2 changing some property:");
   //通过学生s2改变了他所在学校的名称和成立时间
   s2.getSchool().setName("Tianjin University");
   s2.getSchool().setBornYear(1951);
   
   System.out
   .println("s1:" + s1.getName() + " " + s1.getAge() + " "
     + s1.getSchool().getName() + " "
     + s1.getSchool().getBornYear());
   System.out
   .println("s2:" + s2.getName() + " " + s2.getAge() + " "
     + s2.getSchool().getName() + " "
     + s2.getSchool().getBornYear());
 }
  catch (CloneNotSupportedException e)
  {
   e.printStackTrace();
  }
 }
}
class School implements Cloneable
{
 private String name;
 private int bornYear;
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 public int getBornYear()
 {
  return bornYear;
 }
 public void setBornYear(int bornYear)
 {
  this.bornYear = bornYear;
 }
 
 @Override
 protected Object clone() throws CloneNotSupportedException
 {
  return super.clone();
 }
}
class Student implements Cloneable
{
 private int age;
 private String name;
 private School school;
 public School getSchool()
 {
  return school;
 }
 public void setSchool(School school)
 {
  this.school = school;
 }
 public int getAge()
 {
  return age;
 }
 public void setAge(int age)
 {
  this.age = age;
 }
 public String getName()
 {
  return name;
 }
 public void setName(String name)
 {
  this.name = name;
 }
 @Override
 protected Object clone() throws CloneNotSupportedException
 {
  Student s2 = (Student)super.clone();
  
  //将school所引用的对象也拷贝一份,并且让学生s2去引用这个新的School对象
  s2.setSchool((School)school.clone());
  
  return s2;
 }
}
 该段代码让School类(被引用的类)也实现了Cloneable接口,并且也重写了clone()方法。然后改写了Student的clone()方法。从结果可以看出,学生s2改变其引用的学校的属性,不会影响到学生s1所属的学校的属性,这就是深拷贝的含义。还可以通过序列化来实现对象的深拷贝,一个对象被序列化时会将对象和对象内部引用的其他的对象(递归下去)一起序列化一个对象如果想要被序列化,那么必须实现Serializable接口,这个接口也没有定义任何方法,也是一个marker interface

将前一个例子进行改写,用序列化的方法实现深拷贝的代码如下:

view plaincopy to clipboardprint?
package com.test;  
import java.io.ByteArrayInputStream;  
import java.io.ByteArrayOutputStream;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.io.Serializable;  
public class CloneTest  
{  
    public static void main(String[] args) throws Exception  
    {  
        Student s1 = new Student();  
        s1.setAge(20);  
        s1.setName("wudi");  
        School school = new School();  
        school.setName("Peiyang University");  
        school.setBornYear(1895);  
        s1.setSchool(school);  
        System.out  
                .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                        + s1.getSchool().getName() + " " 
                        + s1.getSchool().getBornYear());  
          
        try 
        {  
            //拷贝一个学生  
            Student s2 = (Student)s1.deepClone();  
            s2.setAge(21);  
            s2.setName("WUDI");  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());  
              
            System.out.println("after s2 changing some property:");  
            //通过学生s2改变了他所在学校的名称和成立时间  
            s2.getSchool().setName("Tianjin University");  
            s2.getSchool().setBornYear(1951);   
                
            System.out  
            .println("s1:" + s1.getName() + " " + s1.getAge() + " " 
                    + s1.getSchool().getName() + " " 
                    + s1.getSchool().getBornYear());  
            System.out  
            .println("s2:" + s2.getName() + " " + s2.getAge() + " " 
                    + s2.getSchool().getName() + " " 
                    + s2.getSchool().getBornYear());   
      
        }   
        catch (CloneNotSupportedException e)  
        {  
            e.printStackTrace();  
        }  
    }  
}  
 
class School implements Serializable  
{  
    private String name;  
    private int bornYear;  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }  
    public int getBornYear()  
    {  
        return bornYear;  
    }  
    public void setBornYear(int bornYear)  
    {  
        this.bornYear = bornYear;  
    }  
}  
class Student implements Serializable  
{  
    private int age;  
    private String name;  
    private School school;  
    public School getSchool()  
    {  
        return school;  
    }  
    public void setSchool(School school)  
    {  
        this.school = school;  
    }  
    public int getAge()  
    {  
        return age;  
    }  
    public void setAge(int age)  
    {  
        this.age = age;  
    }  
    public String getName()  
    {  
        return name;  
    }  
    public void setName(String name)  
    {  
        this.name = name;  
    }   
       
    public Object deepClone() throws Exception  
    {  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
          
        //相当于流的连接,将oos流对象连接到baos流对象  
        ObjectOutputStream oos = new ObjectOutputStream(baos);  
          
        oos.writeObject(this);//以上三行将this对象序列化后输出到baos对象中  
          
        //将baos这个流对象转化成字节数组,然后利用这个字节数组构造bais对象  
        //下面三行就是一个反序列化的过程  
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());  
          
        ObjectInputStream ois = new ObjectInputStream(bais);  
          
        return ois.readObject();  
          
    }  
      

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值