前言
在业务开发中,有时需要对业务对象进行一次复制,得到一个一模一样的副本。最直观的做法就是重新 new 一个对象,然后将原型对象的值依次设置到克隆对象中,但是这样写代码过于冗余,也不高效。
设计模式中的原型模式便可以很好的解决这个问题,Java 已经内置了抽象原型接口 Cloneable,只需要实现该接口,便能够通过 clone 方法快速复制一个克隆的对象,应当注意的是,clone 是浅拷贝,如果类中存在引用对象属性,则原型对象和克隆对象的该属性会指向同一个对象引用。
实现深拷贝,有两种方式
- 在调用 super.clone() 后,再依次调用引用对象属性的 clone 方法
- 使用序列化实现
实战代码
浅拷贝
public class Item implements Cloneable, Serializable {private int a;private float b;private double c;private String d;public Item(int a, float b, double c, String d){this.a = a;this.b = b;this.c = c;this.d = d;}public int getA() {return a;}public void setA(int a) {this.a = a;}public float getB() {return b;}public void setB(float b) {this.b = b;}public double getC() {return c;}public void setC(double c) {this.c = c;}public String getD() {return d;}public void setD(String d) {this.d = d;}@Overridepublic String toString() {return "Item{" +"a=" + a +", b=" + b +", c=" + c +", d='" + d + '\'' +'}';}@Overrideprotected Item clone() {Item item = null;try {item = (Item)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return item;}}
深拷贝
public class RefItem implements Cloneable, Serializable {Item item;public RefItem(Item item) {this.item = item;}public Item getItem() {return item;}public void setItem(Item item) {this.item = item;}@Overridepublic String toString() {return "RefItem{" +"item=" + item +'}';}/*** 层层递进调用clone方法* */@Overrideprotected RefItem clone() {RefItem refItem = null;try {refItem = (RefItem)super.clone();refItem.item = refItem.item.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return refItem;}/*** 通过实现Serializable接口* */public static <T extends Serializable> T clone(T obj) {T cloneObj = null;try {// 写入字节流ByteArrayOutputStream out = new ByteArrayOutputStream();ObjectOutputStream obs = new ObjectOutputStream(out);obs.writeObject(obj);obs.close();// 写入原始对象,生成新对象ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());ObjectInputStream ois = new ObjectInputStream(ios);// 返回生成的新对象cloneObj = (T) ois.readObject();ois.close();} catch (Exception e) {e.printStackTrace();}return cloneObj;}}
在 spring 项目中,可直接使用 spring 框架的工具类,将代码简化
/*** 通过实现Serializable接口* */public static <T extends Serializable> T clone(T obj) {return (T) SerializationUtils.deserialize(SerializationUtils.serialize(obj));}