1.假克隆
1.1測試代碼
/**
* 假克隆
* <p>
* 只複製了對象,沒有複製對象的引用
*/
private static void testFakeClone() {
//源對象
Bean bean = new Bean("張三", new Boss("老大"));
//這是克隆對象
Bean clone = bean;
clone.setName("小明");
clone.getBoss().setName("頭");
System.out.println("這是原始數據:");
System.out.println(JSON.toJSONString(bean));
System.out.println("這是假克隆:");
System.out.println(JSON.toJSONString(clone));
}
1.2.輸出結果:
//這是原始數據:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}
//這是假克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}
1.3.結果分析:
這裏,我們修改了克隆對象的屬性之後,源對象的屬性也同樣變了,關係如圖所示(圖是盜來的,不要糾結於名稱):
2.淺克隆
2.1.測試代碼:
/**
* 淺克隆
* <p>
* 既複製了對象,也複製了對象的引用
* 但是如果引用還存在引用,而更深層的引用如果沒有實現cloneable接口,就還是會指向源對象
*/
private static void testShallowClone() {
//源對象
Bean bean = new Bean("張三", new Boss("老大"));
//這是克隆對象
Bean clone = bean.clone();
clone.setName("小明");
clone.getBoss().setName("頭");
System.out.println("這是原始數據:");
System.out.println(JSON.toJSONString(bean));
System.out.println("這是淺克隆:");
System.out.println(JSON.toJSONString(clone));
}
需要Bean實現Cloneable接口:
/**
* 被克隆對象
* <p>
*/
public static class Bean implements Cloneable {
private String name;
private Boss boss;
public Bean() {
}
public Bean(String name, Boss boss) {
this.name = name;
this.boss = boss;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boss getBoss() {
return boss;
}
public void setBoss(Boss boss) {
this.boss = boss;
}
@Override
protected Bean clone() {
Bean clone = null;
try {
clone = (Bean) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
return clone;
}
}
2.2.輸出結果:
//這是原始數據:
{
“boss”: {
“name”: “頭”
},
“name”: “張三”
}
//這是淺克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}
2.3.結果分析:
這裏,我們修改了克隆對象的屬性之後,源對象的name屬性沒有變,但是更深的引用boss卻變了,說明此時源對象和克隆對象所引用的boss對象,其實還是同一個,關係如圖所示(圖是盜來的,不要糾結於名稱):
深克隆
測試代碼:
/**
* 深克隆
* <p>
* 將對象序列化,再反序列化生成一個新對象即可
* Serializable、Parcelable、JSON等均可
*/
private static void testDeepClone() {
//源對象
Bean bean = new Bean("張三", new Boss("老大"));
//這是克隆對象
String json = JSON.toJSONString(bean);
Bean clone = JSON.parseObject(json, Bean.class);
clone.setName("小明");
clone.getBoss().setName("頭");
System.out.println("這是原始數據:");
System.out.println(JSON.toJSONString(bean));
System.out.println("這是深克隆:");
System.out.println(JSON.toJSONString(clone));
}
輸出結果:
//這是原始數據:
{
“boss”: {
“name”: “老大”
},
“name”: “張三”
}
//這是深克隆:
{
“boss”: {
“name”: “頭”
},
“name”: “小明”
}
結果分析:
總結:
- clone在平時項目中雖然用的不多,但是,區分深克隆和淺克隆卻可以幫助我們理解java的內存結構
- clone的深克隆其實就是序列化和反序列化,這裏有很多種選擇,Serializable、Parcelable、JSON等均可
- clone方法不同於new方法,不會執行構造方法
參考目錄:
1. 詳解Java中的clone方法 – 原型模式