zoukankan      html  css  js  c++  java
  • 62 如何实现对象克隆?

    如何实现对象克隆?

    答:

    有两种方式:

    1.实现 Cloneable 接口并重写 Object 类中的 clone() 方法;

    2.实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
     

    原文链接: https://www.baidu.com/link?url=AUgNSLZgNE8RtkM1QGrOd96y8h-W4L0v47H0HlAl9jNsP1qRf2n1qOjLNrP42syd0uWUnj6vMvn7Pf1-WZYZf_&wd=&eqid=b112af76003c1915000000065ec7754a

     

    实现 Cloneable 接口,重写 clone() 方法。

    不实现 Cloneable 接口,会报 CloneNotSupportedException 异常。

    package constxiong.interview;
     
    /**
     * 测试克隆
     * @author ConstXiong
     * @date 2019-06-18 11:21:21
     */
    public class TestClone {
     
    	public static void main(String[] args) throws CloneNotSupportedException {
    		Person p1 = new Person(1, "ConstXiong");//创建对象 Person p1
    		Person p2 = (Person)p1.clone();//克隆对象 p1
    		p2.setName("其不答");//修改 p2的name属性,p1的name未变
    		System.out.println(p1);
    		System.out.println(p2);
    	}
    	
    }
     
    /**
     * 人
     * @author ConstXiong
     * @date 2019-06-18 11:54:35
     */
    class Person implements Cloneable {
    	
    	private int pid;
    	
    	private String name;
    	
    	public Person(int pid, String name) {
    		this.pid = pid;
    		this.name = name;
    		System.out.println("Person constructor call");
    	}
     
    	public int getPid() {
    		return pid;
    	}
     
    	public void setPid(int pid) {
    		this.pid = pid;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
     
    	@Override
    	protected Object clone() throws CloneNotSupportedException {
    		return super.clone();
    	}
     
    	@Override
    	public String toString() {
    		return "Person [pid:"+pid+", name:"+name+"]";
    	}
    	
    }
    

     

    打印结果:

    Person constructor call
    Person [pid:1, name:ConstXiong]
    Person [pid:1, name:其不答]
    

    Object 的 clone() 方法是浅拷贝,即如果类中属性有自定义引用类型,只拷贝引用,不拷贝引用指向的对象。

     

    可以使用下面的两种方法,完成 Person 对象的深拷贝。

     

    方法1、对象的属性的Class 也实现 Cloneable 接口,在克隆对象时也手动克隆属性。

      
        @Override
    	public Object clone() throws CloneNotSupportedException {
    		DPerson p = (DPerson)super.clone();
    		p.setFood((DFood)p.getFood().clone());
    		return p;
    	}
    

     

    完整代码:

     
    /**
     * 测试克隆
     * @author ConstXiong
     * @date 2019-06-18 11:21:21
     */
    public class TestManalDeepClone {
     
    	public static void main(String[] args) throws Exception {
    		DPerson p1 = new DPerson(1, "ConstXiong", new DFood("米饭"));//创建Person 对象 p1
    		DPerson p2 = (DPerson)p1.clone();//克隆p1
    		p2.setName("其不答");//修改p2的name属性
    		p2.getFood().setName("面条");//修改p2的自定义引用类型 food 属性
    		System.out.println(p1);//修改p2的自定义引用类型 food 属性被改变,p1的自定义引用类型 food 属性也随之改变,说明p2的food属性,只拷贝了引用,没有拷贝food对象
    		System.out.println(p2);
    	}
    	
    }
     
    class DPerson implements Cloneable {
    	
    	private int pid;
    	
    	private String name;
    	
    	private DFood food;
    	
    	public DPerson(int pid, String name, DFood food) {
    		this.pid = pid;
    		this.name = name;
    		this.food = food;
    		System.out.println("Person constructor call");
    	}
     
    	public int getPid() {
    		return pid;
    	}
     
    	public void setPid(int pid) {
    		this.pid = pid;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
     
    	@Override
    	public Object clone() throws CloneNotSupportedException {
    		DPerson p = (DPerson)super.clone();
    		p.setFood((DFood)p.getFood().clone());
    		return p;
    	}
     
    	@Override
    	public String toString() {
    		return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";
    	}
     
    	public DFood getFood() {
    		return food;
    	}
     
    	public void setFood(DFood food) {
    		this.food = food;
    	}
    	
    }
     
    class DFood implements Cloneable{
    	
    	private String name;
    	
    	public DFood(String name) {
    		this.name = name;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
     
    	@Override
    	public Object clone() throws CloneNotSupportedException {
    		return super.clone();
    	}
    	
    }
    

     

    打印结果:

    Person constructor call
    Person [pid:1, name:ConstXiong, food:米饭]
    Person [pid:1, name:其不答, food:面条]
    

     

    方法2、结合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷贝

    结合 java.io.Serializable 接口,完成深拷贝

    package constxiong.interview;
     
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
     
    public class TestSeriazableClone {
     
    	public static void main(String[] args) {
    		SPerson p1 = new SPerson(1, "ConstXiong", new SFood("米饭"));//创建 SPerson 对象 p1
    		SPerson p2 = (SPerson)p1.cloneBySerializable();//克隆 p1
    		p2.setName("其不答");//修改 p2 的 name 属性
    		p2.getFood().setName("面条");//修改 p2 的自定义引用类型 food 属性
    		System.out.println(p1);//修改 p2 的自定义引用类型 food 属性被改变,p1的自定义引用类型 food 属性未随之改变,说明p2的food属性,只拷贝了引用和 food 对象
    		System.out.println(p2);
    	}
    	
    }
     
    class SPerson implements Cloneable, Serializable {
    	
    	private static final long serialVersionUID = -7710144514831611031L;
     
    	private int pid;
    	
    	private String name;
    	
    	private SFood food;
    	
    	public SPerson(int pid, String name, SFood food) {
    		this.pid = pid;
    		this.name = name;
    		this.food = food;
    		System.out.println("Person constructor call");
    	}
     
    	public int getPid() {
    		return pid;
    	}
     
    	public void setPid(int pid) {
    		this.pid = pid;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
     
    	/**
    	 * 通过序列化完成克隆
    	 * @return
    	 */
    	public Object cloneBySerializable() {
    		Object obj = null;
    		try {
    			ByteArrayOutputStream baos = new ByteArrayOutputStream();
    			ObjectOutputStream oos = new ObjectOutputStream(baos);
    			oos.writeObject(this);
    			ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    			ObjectInputStream ois = new ObjectInputStream(bais);
    			obj = ois.readObject();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    		return obj;
    	}
     
    	@Override
    	public String toString() {
    		return "Person [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";
    	}
     
    	public SFood getFood() {
    		return food;
    	}
     
    	public void setFood(SFood food) {
    		this.food = food;
    	}
    	
    }
     
    class SFood implements Serializable {
    	
    	private static final long serialVersionUID = -3443815804346831432L;
    	
    	private String name;
    	
    	public SFood(String name) {
    		this.name = name;
    	}
     
    	public String getName() {
    		return name;
    	}
     
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    }
    

     

    打印结果:

    Person constructor call
    Person [pid:1, name:ConstXiong, food:米饭]
    Person [pid:1, name:其不答, food:面条]
    

     

  • 相关阅读:
    从零搭建springboot+mybatis逆向工程
    基础SQL总结
    Map集合浅谈
    ArrayList、LinkedList与Vector的区别
    java多线程总结
    P4108 [HEOI2015]公约数数列
    P2168 [NOI2015] 荷马史诗
    正睿 2021 Noip 十连测 Day2
    CF772E Verifying Kingdom
    BZOJ1767 [CEOI2009] Harbingers
  • 原文地址:https://www.cnblogs.com/ynzj123/p/12937091.html
Copyright © 2011-2022 走看看