实现 Cloneable 方式
浅拷贝
@AllArgsConstructor
public class Result implements Serializable, Cloneable {
@Getter
@Setter
private int code;
@Getter
@Setter
private String message;
@Getter
@Setter
private Data data;
@Override
public Result clone() throws CloneNotSupportedException {
return (Result) super.clone();
}
}
@AllArgsConstructor
public class Data implements Serializable {
@Getter
@Setter
private String requestId;
@Getter
@Setter
private String fileName;
}
public class AnswerApp {
public static void main(String[] args) throws Exception {
Result result = new Result(10000, "success", new Data("1_F63BF87F4B104E9E8594AC188EBA0E03", "answer.md"));
System.out.println(JacksonUtil.toJsonString(result));
// 浅拷贝
Result clone = result.clone();
// 打印对象地址
System.out.println(result);
System.out.println(clone);
// 对比克隆前后对象属性
System.out.println(clone.getData() == result.getData());
System.out.println(clone.getMessage() == result.getMessage());
clone.setMessage("upload success");
clone.getData().setFileName("answer.zip");
System.out.println(JacksonUtil.toJsonString(result));
System.out.println(JacksonUtil.toJsonString(clone));
}
}
程序运行结果
{"code":10000,"message":"success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.md"}}
com.xiwei.xn.entity.Result@5c3bd550
com.xiwei.xn.entity.Result@91161c7
true
true
{"code":10000,"message":"success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.zip"}}
{"code":10000,"message":"upload success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.zip"}}
从运行结果看: result 和 clone 两个对象的地址是不同的,也就是说 调用 clone 方法时创建了新的对象。 但是对象内的属性的地址是一样的且修改了 clone 对象的属性值, result 对象的属性值也跟着变化, 因此克隆时, 对象内的属性只是将引用赋值给新拷贝的对象的对应的属性
结论: 一个类实现了 Cloneable 接口, 如果不对 clone 方法进行重写, 只是简单的调用 Object 类的 clone 方法, 则对象的拷贝是浅拷贝(创建了新对象, 但是对象内的属性字段克隆前后都是指向同一个堆地址, 如果对克隆后的对象进行属性修改, 克隆前后的两个对象的对应属性都会被修改)
深拷贝
@AllArgsConstructor
public class Result implements Serializable, Cloneable {
@Getter
@Setter
private int code;
@Getter
@Setter
private String message;
@Getter
@Setter
private Data data;
@Override
public Result clone() throws CloneNotSupportedException {
Result result = (Result) super.clone();
// 需要对 result 内的属性进行重新创建对象
result.message = new String(message);
result.data = data.clone();
return result;
}
}
@AllArgsConstructor
public class Data implements Serializable, Cloneable {
@Getter
@Setter
private String requestId;
@Getter
@Setter
private String fileName;
@Override
protected Data clone() throws CloneNotSupportedException {
return (Data) super.clone();
}
}
public class AnswerApp {
public static void main(String[] args) throws Exception {
Result result = new Result(10000, "success", new Data("1_F63BF87F4B104E9E8594AC188EBA0E03", "answer.md"));
System.out.println(JacksonUtil.toJsonString(result));
// 深拷贝, 因为 clone 方法内对对象的属性进行重新创建并赋值
Result clone = result.clone();
System.out.println(result);
System.out.println(clone);
System.out.println(clone.getData() == result.getData());
System.out.println(clone.getMessage() == result.getMessage());
clone.setMessage("upload success");
clone.getData().setFileName("answer.zip");
System.out.println(JacksonUtil.toJsonString(result));
System.out.println(JacksonUtil.toJsonString(clone));
}
}
程序运行结果
{"code":10000,"message":"success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.md"}}
com.xiwei.xn.entity.Result@5c3bd550
com.xiwei.xn.entity.Result@91161c7
false
false
{"code":10000,"message":"success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.md"}}
{"code":10000,"message":"upload success","data":{"requestId":"1_F63BF87F4B104E9E8594AC188EBA0E03","fileName":"answer.zip"}}
序列化方式实现深拷贝
@SuppressWarnings("unchecked")
public static <T> T clone(T obj) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
return (T) ois.readObject();
}