对象的复制(浅复制与深复制)

Posted seven_hu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对象的复制(浅复制与深复制)相关的知识,希望对你有一定的参考价值。

    在Java中如果想将一个基本类型变量的值赋给另一个变量,直接使用等号解可以了,原始的版本改变了,副本并不会发生变化,如下:

int a=10;
int b=a;
a=9;
System.out.println(a); //9
System.out.println(b); //10

   但是如果想要复制的变量不是基本类型,而是引用类型的话,就会与上面的效果不同:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
public class People {
    private int age;
    private String name;
    public People(int age,String name){
        this.age=age;
        this.name=name;
    }

    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 String toString(){
        return this.name+" is "+this.age;
    }
    public static void main(String[] args){
        People p1=new People(12,"tom");
        People p2=p1;
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12
* tom is 12
* jack is 25
* jack is 25
* */     

      在上面的代码中,原始对象发生变化,副本对象也发生了变化,这是因为,执行p2=p1这段代码的时候,只是发生了引用变量的复制,而并没有发生对象的复制,两个引用变量指向的还是同一个对象。

那么,怎样才能达到复制一个对象呢?
  是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:

      protected native Object clone() throws CloneNotSupportedException;

一般步骤是(浅复制):

1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)

2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)

对上面的代码进行改造,如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
public class People implements Cloneable{
    private int age;
    private String name;
    public People(int age,String name){
        this.age=age;
        this.name=name;
    }

    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 String toString(){
        return this.name+" is "+this.age;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }
    public static void main(String[] args){
        People p1=new People(12,"tom");
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12
* tom is 12
* jack is 25
* tom is 12
* */

 那么我们还可以在People中再添加一个Address类,如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
class Address{
    private String address;
    public Address(String address){
        this.address=address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString(){
        return address;
    }
}
public class People implements Cloneable{
    private int age;
    private String name;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public People(int age,String name){
        this.age=age;
        this.name=name;
    }
    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 String toString(){
        return this.name+" is "+this.age+", live in "+address;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return people;
    }
    public static void main(String[] args){
        Address address=new Address("LuoYang");
        People p1=new People(12,"tom");
        p1.setAddress(address);
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        address.setAddress("ZhengZhou");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12, live in LuoYang
* tom is 12, live in LuoYang
* jack is 25, live in ZhengZhou
* tom is 12, live in ZhengZhou
* */

上面的代码,原始的版本对象地址发生了变化,但是副本却没有发生变化,那是因为在进行复制时,只复制了address这个变量的引用,并没有复制该变量指向的对象。此时就需要深度复制,深度复制很简单,只需要将Address也实现Cloneable接口即可,修改如下:

package demos;
/**
 * Created by hu on 2016/3/26.
 */
class Address implements Cloneable{
    private String address;
    public Address(String address){
        this.address=address;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString(){
        return address;
    }
    @Override
    public Object clone(){
        Address address = null;
        try{
            address = (Address)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return address;
    }
}
public class People implements Cloneable{
    private int age;
    private String name;
    private Address address;

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public People(int age,String name){
        this.age=age;
        this.name=name;
    }
    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 String toString(){
        return this.name+" is "+this.age+", live in "+address;
    }
    @Override
    public Object clone(){
        People people = null;
        try{
            people = (People)super.clone();
        }catch(CloneNotSupportedException e) {
            e.printStackTrace();
        }
        people.setAddress((Address) people.getAddress().clone());
        return people;
    }
    public static void main(String[] args){
        Address address=new Address("LuoYang");
        People p1=new People(12,"tom");
        p1.setAddress(address);
        People p2= (People) p1.clone();
        System.out.println(p1);
        System.out.println(p2);
        p1.setAge(25);
        p1.setName("jack");
        address.setAddress("ZhengZhou");
        System.out.println(p1);
        System.out.println(p2);
    }
}
/*output:
* tom is 12, live in LuoYang
* tom is 12, live in LuoYang
* jack is 25, live in ZhengZhou
* tom is 12, live in LuoYang
* */

  如此,就是深度复制了。

     总结:浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,没有对引用指向的对象进行拷贝。而深拷贝是指在拷贝对象时,同时会对引用指向的对象进行拷贝。区别就在于是否对对象中的引用变量所指向的对象进行拷贝。

 

以上是关于对象的复制(浅复制与深复制)的主要内容,如果未能解决你的问题,请参考以下文章

PHP浅复制与深复制

Javascript 浅复制与深复制

Python浅拷贝copy()与深拷贝deepcopy()区别

python变量及浅复制与深复制

python基础之浅复制与深复制

python之copy模块与深拷贝浅拷贝