【Java基础】Java浅拷贝和深拷贝

时间:2021-07-23 19:49:36
package com.pachira.c;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/*
 * Java的浅拷贝和深拷贝
 * 【浅拷贝】:重写Object的clone()方法且实现Cloneable这个空接口(规则如下):
 * +---------------------------------------------------------------------------------------------+
 * | 基本类型 | 拷贝其值,比如int、float等。                                                         |
 * +---------------------------------------------------------------------------------------------+
 * | String | 拷贝其地址引用,但在修改时,它从字符串池中重新生成一个新字符串,原有字符串对象保持不变。       |
 * +---------------------------------------------------------------------------------------------+
 * | 对象    | 拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。                              |
 * +---------------------------------------------------------------------------------------------+
 * 
 * 【深拷贝】:利用序列化实现对象的拷贝:
 * 原理:把母对象写入到一个字节流中,再从字节流中将其读出来,这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。
 * 注意:被克隆的对象需要实现Serializable接口
 * 
 * 参考:
 * http://cmsblogs.com/?p=58
 * http://www.cnblogs.com/chenssy/p/3308489.html
 */
public class LClone implements Cloneable, Serializable{
	private static final long serialVersionUID = -1991475817161553683L;
	
	private int id;
	private String name;
	private Email email;
	
	public LClone() {
	}
	public LClone(int id, String name, Email email) {
		this.id = id;
		this.name = name;
		this.email = email;
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public Email getEmail() {
		return email;
	}
	
	public void setEmail(Email email) {
		this.email = email;
	}
	public LClone clone() throws CloneNotSupportedException {
		return (LClone)super.clone();
	}
	@Override
	public String toString() {
		return "id: " + this.id + ", name: " + this.name + ", email: " + this.email;
	}

	public static void main(String[] args) throws CloneNotSupportedException {
		Email email = new LClone.Email("welcome.");
		LClone stu = new LClone(2, "Tom", email);
		LClone stu2 = stu.clone();
		stu2.setId(3);
		stu2.setName("Jim");
		System.out.println(stu);
		System.out.println(stu2);
		System.out.println(stu.getEmail() == stu2.getEmail());
		
		CloneUtil cloneUtil = new LClone.CloneUtil();
		LClone stu3 = cloneUtil.clone(stu);
		System.out.println(stu.getEmail() == stu3.getEmail());
//		id: 2, name: Tom, email: welcome.
//		id: 3, name: Jim, email: welcome.
//		true
//		false
	}
	
	static class Email implements Serializable{
		private static final long serialVersionUID = 717077025366523218L;

		private String content;
		
		public String getContent() {
			return content;
		}
		public void setContent(String content) {
			this.content = content;
		}
		
		public Email(String content) {
			this.content = content;
		}
		@Override
		public String toString() {
			return this.content;
		}
	}
	static class CloneUtil {
		@SuppressWarnings("unchecked")
		public <T extends Serializable> T clone(T obj){
			T newT = null;
			try {
				//写入字节流
	            ByteArrayOutputStream out = new ByteArrayOutputStream();
	            ObjectOutputStream obs = new ObjectOutputStream(out);
	            obs.writeObject(obj);
	            obs.close();
	            //分配内存,写入原始对象,生成新对象
	            ByteArrayInputStream bais = new ByteArrayInputStream(out.toByteArray());
	            ObjectInputStream ois = new ObjectInputStream(bais);
	            //返回生成的新对象
	            newT = (T) ois.readObject();
	            ois.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			return newT;
		}
	}
}