➢原理结构图说明
Prototype: 原型类,声明一个克隆自己的接口ConcretePrototype: 具体的原型类,实现-一个克隆自己的操作Client: 让一个原型对象克隆自己,从而创建一一个新的对象(属性一样)浅克隆,如果被克隆类有一个属性是其他的对象,那么它克隆出来的对象会互相干扰。
package com.xhl.prototype; //浅克隆,如果克隆location就会相互影响 public class Text { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person p1 = new Person(); Person p2 = (Person)p1.clone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person implements Cloneable{ int age = 8; int score = 100; Location loc = new Location("bj",22); @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } } class Location{ String street; int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } }原因: 总结:
对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。第一种方法
package com.xhl.prototype; //深克隆 public class Text1 { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person1 p1 = new Person1(); Person1 p2 = (Person1)p1.clone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person1 implements Cloneable{ int age = 8; int score = 100; Location1 loc = new Location1("bj",22); @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Person1 p = (Person1)super.clone(); p.loc = (Location1)loc.clone(); return p; } } class Location1 implements Cloneable{ String street; /* * String类型也是引用类型, * 但是不需要进行深克隆 * 因为String类型指向的是一个常量池 * 本身就是共用的 */ int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location1(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone(); } }第二种方法
package com.xhl.prototype; //深克隆 import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class Text1 { public static void main(String[] args) throws CloneNotSupportedException { // TODO Auto-generated method stu Person1 p1 = new Person1(); //Person1 p2 = (Person1)p1.clone(); Person1 p2 = (Person1) p1.deepClone(); System.out.println(p2.age+" "+p2.score); System.out.println(p2.loc); System.out.println(p1.loc==p2.loc); p1.loc.street="sh"; System.out.println(p2.loc); } } class Person1 implements Cloneable,Serializable{ int age = 8; int score = 100; Location1 loc = new Location1("bj",22); //方法一 @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub Person1 p = (Person1)super.clone(); p.loc = (Location1)loc.clone(); return p; } //方法二 通过对象序列化实现 public Object deepClone() { ByteArrayOutputStream bos = null; ObjectOutputStream oos = null; ByteArrayInputStream bis = null; ObjectInputStream ois = null; try { //序列化 bos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(bos); oos.writeObject(this); //反序列化 bis = new ByteArrayInputStream(bos.toByteArray()); ois = new ObjectInputStream(bis); Person1 p = (Person1)ois.readObject(); return p; } catch (Exception e) { // TODO: handle exception e.printStackTrace(); return null; }finally { try { bos.close(); oos.close(); bis.close(); ois.close(); } catch (Exception e2) { // TODO: handle exception System.out.println(e2.getMessage()); } } } } class Location1 implements Cloneable,Serializable{ String street; /* * String类型也是引用类型, * 但是不需要进行深克隆 * 因为String类型指向的是一个常量池 * 本身就是共用的 */ int roomNo; @Override public String toString() { // TODO Auto-generated method stub return "Lacation["+ "street='"+street+ ",roomNo="+roomNo+ "]"; } public Location1(String street, int roomNo) { super(); this.street = street; this.roomNo = roomNo; } @Override protected Object clone() throws CloneNotSupportedException { // TODO Auto-generated method stub return super.clone();总结:
复制对象的所有基本数据类型的成员变量值为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝