测试代码
public class Client { public static void main(String[] args) { //创建原型对象 ConcretePrototype prototype = new ConcretePrototype(); prototype.setAge(18); prototype.setName("Tom"); System.out.println(prototype); //拷贝原型对象 ConcretePrototype cloneType = prototype.clone(); System.out.println(cloneType); } }
运行结果:
在实际编码中,我们一般不会浪费这样的体力劳动,JDK已经帮我们实现了一个现成的API,我们只需要实现Cloneable接口即可。来改造一下代码,修改ConcretePrototype类:
@Data public class ConcretePrototype implements Cloneable { private int age; private String name; private List<String> hobbies; @Override public ConcretePrototype clone() { try { return (ConcretePrototype)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + ", hobbies=" + hobbies + '}'; } }
写一个测试用例
public class Client { public static void main(String[] args) { //创建原型对象 ConcretePrototype prototype = new ConcretePrototype(); prototype.setAge(18); prototype.setName("Tom"); List<String> hobbies = new ArrayList<String>(); hobbies.add("书法"); hobbies.add("美术"); prototype.setHobbies(hobbies); //拷贝原型对象 ConcretePrototype cloneType = prototype.clone(); cloneType.getHobbies().add("技术控"); System.out.println("原型对象:" + prototype); System.out.println("克隆对象:" + cloneType); System.out.println(prototype == cloneType); System.out.println("原型对象的爱好:" + prototype.getHobbies()); System.out.println("克隆对象的爱好:" + cloneType.getHobbies()); System.out.println(prototype.getHobbies() == cloneType.getHobbies()); } }
运行结果
我们给复制后的克隆对象新增一项爱好,发现原型对象也发生了变化,这显然不符合我们的预期。因为我们希望克隆出来的对象应该和原型对象是两个独立的对象,不应该再有联系了。从测试结果分析来看,应该是hobies共用了一个内存地址,意味着复制的不是值,而是引用的地址。这样的话,如果我们修改的是一个对象中的属性值,prototype和cloneType的hobbies值都会改变。这就是我们常说的浅克隆。只是完整复制了值类型数据,没有复制引用对象。换言之,所有的引用对象仍然指向原来的对象,显然不是我们想要的结果。下面我们引入深克隆继续改造。
使用序列化实现深度克隆
在上面的基础上,我们继续改造,来看代码,增加一个deepClone()方法:
@Data public class ConcretePrototype implements Cloneable,Serializable { private int age; private String name; private List<String> hobbies; @Override public ConcretePrototype clone() { try { return (ConcretePrototype)super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } public ConcretePrototype deepCloneHobbies(){ try { ConcretePrototype result = (ConcretePrototype)super.clone(); result.hobbies = (List)((ArrayList)result.hobbies).clone(); return result; } catch (CloneNotSupportedException e) { e.printStackTrace(); return null; } } public ConcretePrototype deepClone(){ try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (ConcretePrototype)ois.readObject(); }catch (Exception e){ e.printStackTrace(); return null; } } @Override public String toString() { return "ConcretePrototype{" + "age=" + age + ", name='" + name + '\'' + ", hobbies=" + hobbies + '}'; } }
测试代码