java中的对象克隆(浅克隆和深克隆)

在实际项目中,一个模型类需要为不同的层提供不同的模型。VO DO DTO

java中的对象克隆(浅克隆和深克隆)_第1张图片

需要将一个对象中的数据克隆到其他对象中。

误区这种形式的代码复制的是引用,即对象在内存中的地址,stu1和stu2两个引用指向的是同一个对象

java中的对象克隆(浅克隆和深克隆)_第2张图片

Student stu1 = new Student(); 
Student stu2 = stu1; 

数据类型分为:基本数据类型和引用数据类型,基本类型的值可以直接复制,引用类型只能复制引用地址。所以浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制

1、浅克隆

在克隆一个对象时,只复制它本身和其中值类型的成员变量,如果有关联的对象,只是将关联对象的引用地址复制过来,并没有创建一个新的关联对象。

java中的对象克隆(浅克隆和深克隆)_第3张图片java中的对象克隆(浅克隆和深克隆)_第4张图片

实现方式:类实现Cloneable接口,重写Object中的clone方法  

package com.ffyc.javapro.objectClone.demo1;
public class Person implements  Cloneable{
    int num;
    String name;
    
    //get和set方法...

    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                '}';
    }
}
package com.ffyc.javapro.objectClone.demo1;
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p1 = new Person(100,"jim");//原型对象
        Person p2 =p1.clone();//克隆的新对象
        System.out.println(p1==p2);//false,实现了克隆
    }
}

以下案例中,有关联的对象address,只是将关联的对象的引用地址复制过来,并没有新创建关联对象,为浅克隆。

public class Address{
    String  address;
	//get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();//对象中关联着另一个对象,只是将关联对象的地址复制过来了,并没有重新创建一个新的关联对象
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向了一个对象

        System.out.println(p1); // jim  西安
        System.out.println(p2); // tom  西安
    }
}

2、深克隆

无论原型对象的成员变量是值类型还是引用类型(关联的对象),都将复制一份给克隆对象。(如果有关联的对象,将关联对象也会重新创建一个)

java中的对象克隆(浅克隆和深克隆)_第5张图片

克隆方式:

  1. 在关联的对象中,也实现Cloneable接口,重写Object中的clone方法,实现多级克隆,但是处理起来比较麻烦。
  2. 使用序列化方式,可以重写创建对象,包含关联的对象。

案例一:相关联的类address也实现了Cloneable接口,重写Object中的clone方法,为深度克隆,但是很麻烦。

public class Address  implements Cloneable{//实现了Cloneable接口
    String  address;
   //get和set方法...
    
    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }

    @Override
    protected Address clone() throws CloneNotSupportedException {//重写Object中的clone方法
        return (Address)super.clone();
    }
}
public class Person implements  Cloneable{
     int num;
     String name;
     Address address;   
	//get和set方法...
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person person = (Person)super.clone();
        person.address = (Address)address.clone();//深度复制  联同person中关联的对象也一同克隆.
        return person;
    }

    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.clone();
        p2.setName("tom");
        address.setAddress("西安");//adress为汉中改为西安,p1和p2都指向不同的对象

        System.out.println(p1); // jim   西安
        System.out.println(p2); // tom   汉中
    }
}

案例二:实现了Serializable。把Person写到流里面,然后读进来,重新创建一个对象

import java.io.Serializable;
public class Address  implements Serializable {
     String  address;
    //get和set方法...

    @Override
    public String toString() {
        return "Address{" +
                "address='" + address + '\'' +
                '}';
    }
}
import java.io.*;
public class Person implements Serializable {
     int num;
     String name;
     Address address;
    //get和set方法...
    
    //自定义克隆方法
    public Person myclone() {
        Person person = null;
          try { // 将该对象序列化成流,因为写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面。所以利用这个特性可以实现对象的深拷贝
                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
                  ObjectOutputStream oos = new ObjectOutputStream(baos);
                  oos.writeObject(this);
        		// 将流序列化成对象
                ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
                 ObjectInputStream ois = new ObjectInputStream(bais);
                 person = (Person) ois.readObject();
              } catch (IOException e) {
                 e.printStackTrace();
              } catch (ClassNotFoundException e) {
                 e.printStackTrace();
             }
         return person;
      }


    @Override
    public String toString() {
        return "Person{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", address=" + address +
                '}';
    }
}
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Address address = new Address();
        address.setAddress("汉中");

        Person p1 = new  Person(100,"jim");
        p1.setAddress(address);

        Person p2 =p1.myclone();
        p2.setName("tom");
        address.setAddress("西安");

        System.out.println(p1);
        System.out.println(p2);
    }
}

你可能感兴趣的:(java,开发语言)