目录
前言
在业务开发中,有时需要对业务对象进行一次复制,得到一个一模一样的副本。最直观的做法就是重新 new 一个对象,然后将原型对象的值依次设置到克隆对象中,但是这样写代码过于冗余,也不高效。
设计模式中的原型模式便可以很好的解决这个问题,Java 已经内置了抽象原型接口 Cloneable,只需要实现该接口,便能够通过 clone 方法快速复制一个克隆的对象,应当注意的是,clone 是浅拷贝,如果类中存在引用对象属性,则原型对象和克隆对象的该属性会指向同一个对象引用。
实现深拷贝,有两种方式
- 在调用 super.clone() 后,再依次调用引用对象属性的 clone 方法
- 使用序列化实现
UML
plantuml
@startuml 'https://plantuml.com/class-diagram interface Cloneable { + clone() : type } class Item { - field : type + clone() : Item } class Client { + {static} main(String[]) : void } Cloneable <|.. Item Client ..> Item @enduml
类图
实战代码
浅拷贝
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;
}
@Override
public String toString() {
return "Item{" +
"a=" + a +
", b=" + b +
", c=" + c +
", d='" + d + '\'' +
'}';
}
@Override
protected 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;
}
@Override
public String toString() {
return "RefItem{" +
"item=" + item +
'}';
}
/**
* 层层递进调用clone方法
* */
@Override
protected 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));
}