该模式的作用就是复制对象,特别是复杂的对象。
1.浅克隆
两个要点:实现Cloneable接口,重写clone()方法
public class Product implements Cloneable{ private String name; private Date date; public Product(String name, Date date) { this.name = name; this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", date=" + date + '}'; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
测试结果:
//浅克隆 public static void main(String[] args) throws CloneNotSupportedException { Date date1 = new Date(); Product product = new Product("张三",date1); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); Product cloneProduct = (Product) product.clone(); System.out.println("v2=>"+cloneProduct+" hashcode=>"+cloneProduct.hashCode()); date1.setTime(22223333); System.out.println("===========修改属性后========"); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); System.out.println("v2=>"+cloneProduct+" hashcode=>"+cloneProduct.hashCode()); }
打印结果:
v1=>Product{name='张三', date=Sun Apr 18 16:45:56 CST 2021} hashcode=>1836019240 v2=>Product{name='张三', date=Sun Apr 18 16:45:56 CST 2021} hashcode=>325040804 ===========修改属性后======== v1=>Product{name='张三', date=Thu Jan 01 14:10:23 CST 1970} hashcode=>1836019240 v2=>Product{name='张三', date=Thu Jan 01 14:10:23 CST 1970} hashcode=>325040804
结论:原对象和克隆对象的date属性是同一个
2.深克隆
解决上个案例中date属性指向同一个问题。
public class Product implements Cloneable{ private String name; private Date date; public Product(String name, Date date) { this.name = name; this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", date=" + date + '}'; } @Override protected Object clone() throws CloneNotSupportedException { Product product = (Product)super.clone(); product.date = (Date) this.date.clone(); return product; } }
测试结果
//深克隆 public static void main(String[] args) throws CloneNotSupportedException { Date date1 = new Date(); Product product = new Product("张三",date1); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); Product cloneProduct = (Product) product.clone(); System.out.println("v2=>"+cloneProduct+" hashcode=>"+cloneProduct.hashCode()); date1.setTime(22223333); System.out.println("===========修改属性后========"); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); System.out.println("v2=>"+cloneProduct+" hashcode=>"+cloneProduct.hashCode()); }
打印:
v1=>Product{name='张三', date=Sun Apr 18 16:56:55 CST 2021} hashcode=>1836019240 v2=>Product{name='张三', date=Sun Apr 18 16:56:55 CST 2021} hashcode=>325040804 ===========修改属性后======== v1=>Product{name='张三', date=Thu Jan 01 14:10:23 CST 1970} hashcode=>1836019240 v2=>Product{name='张三', date=Sun Apr 18 16:56:55 CST 2021} hashcode=>325040804
结论:实现的深克隆,date对象也成功克隆,这里有个前提,Date类也实现了Cloneable接口才行。
3.通过序列化来复制对象
深度克隆有个问题:所有属性都要克隆,属性下面可能还有属性,需要层层克隆,非常麻烦,通过流来复制可以减少这些麻烦,但是IO流会增加系统消耗。
前提是被序列化的对象实现Serializable接口,包括它的层层下面的属性,如果某个属性不想序列化,可以通过一些注解来忽略。
public class Product implements Serializable { private String name; private Date date; public Product(String name, Date date) { this.name = name; this.date = date; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @Override public String toString() { return "Product{" + "name='" + name + '\'' + ", date=" + date + '}'; } }
测试代码
public class CloneObject { public static void main(String[] args) { Date date1 = new Date(); Product product = new Product("张三",date1); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); Product product1 = cloneUtil.cloneObject(product); System.out.println("v2=>"+product1 +" hashcode=>"+product1.hashCode()); date1.setTime(22223333); System.out.println("===========修改属性后========"); System.out.println("v1=>"+product +" hashcode=>"+product.hashCode()); System.out.println("v2=>"+product1 +" hashcode=>"+product1.hashCode()); } } class cloneUtil { private cloneUtil() { } @SuppressWarnings("unchecked") public static <T extends Serializable> T cloneObject(T obj) { T cloneObj = null; // 序列化 ByteArrayOutputStream bout = null; ObjectOutputStream oos = null; try { bout = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bout); oos.writeObject(obj); } catch (IOException e) { e.printStackTrace(); } finally { close(oos); close(bout); } // 反序列化 ByteArrayInputStream bin = null; ObjectInputStream ois = null; try { bin = new ByteArrayInputStream(bout.toByteArray()); ois = new ObjectInputStream(bin); cloneObj = (T) ois.readObject(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { close(ois); close(bin); } return cloneObj; } private static void close(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (Exception e) { e.printStackTrace(); } } } }
打印结果:
v1=>Product{name='张三', date=Sun Apr 18 17:03:19 CST 2021} hashcode=>1836019240 v2=>Product{name='张三', date=Sun Apr 18 17:03:19 CST 2021} hashcode=>1072408673 ===========修改属性后======== v1=>Product{name='张三', date=Thu Jan 01 14:10:23 CST 1970} hashcode=>1836019240 v2=>Product{name='张三', date=Sun Apr 18 17:03:19 CST 2021} hashcode=>1072408673