簡介
實現Cloneable接口的類纔可以被克隆,如果不實現該接口,調用Object clone方法會報CloneNotSupportedException:
InvokingObject's clone method on an instance that does not implement theCloneableinterface results in the exceptionCloneNotSupportedExceptionbeing thrown.
分類
- 淺克隆 指拷貝對象時僅拷貝對象本身中的基本變量,而不拷貝對象包含的引用指向的對象
- 深克隆 不僅拷貝對象本身中的基本變量,而且還拷貝對象中包含的引用指向的所有對象
說明
package com.lios.clone; /** * @author LiosWong * @description * @date 2018/6/25 上午4:11 */ public class Person implements Cloneable { private String name; private Worker worker; public Person(String name, Worker worker) { this.name = name; this.worker = worker; } public String getName() { return name; } public Person setName(String name) { this.name = name; return this; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public static void main(String[] args) { Person p = new Person("lios", new Worker("worker", 25)); Person p1 = p; System.out.println("p:toString:" + p + ",hashCode:" + p.hashCode() + ",Worker:" + p.getWorker().hashCode() + ",name=" + p.getName().hashCode()); System.out.println("p1:toString:" + p1 + ",hashCode:" + p1.hashCode() + ",Worker:" + p1.getWorker().hashCode() + ",name=" + p1.getName().hashCode()); System.out.println(p1); System.out.println("====================="); try { Person p2 = (Person) p.clone(); System.out.println("p:Worker:name:"+p.getWorker().getName()); System.out.println("p1:Worker:name:"+p1.getWorker().getName()); System.out.println("p2:Worker:name:"+p2.getWorker().getName()); System.out.println("p2:toString:" + p2 + ",hashCode:" + p2.hashCode() + ",Worker:" + p2.getWorker().hashCode() + ",name=" + p2.getName().hashCode()); p.getWorker().setName("workp"); p.setName("cc"); System.out.println("p2:toString:" + p2 + ",hashCode:" + p2.hashCode() + ",Worker:" + p2.getWorker().hashCode() + ",name=" + p2.getName().hashCode()); System.out.println("p:Worker:name:"+p.getWorker().getName()); System.out.println("p1:Worker:name:"+p1.getWorker().getName()); System.out.println("p2:Worker:name:"+p2.getWorker().getName()); System.out.println("p:"+p.getName()); System.out.println("p1:"+p1.getName()); System.out.println("p2:"+p2.getName()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } public Worker getWorker() { return worker; } public Person setWorker(Worker worker) { this.worker = worker; return this; } public static class Worker implements Cloneable { private String name; private Integer age; public Worker(String name, Integer age) { this.name = name; this.age = age; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public String getName() { return name; } public Worker setName(String name) { this.name = name; return this; } public Integer getAge() { return age; } public Worker setAge(Integer age) { this.age = age; return this; } } }
執行結果爲:
p:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889 p1:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889 com.lios.clone.Person@2401f4c3 ===================== p:Worker:name:worker p1:Worker:name:worker p2:Worker:name:worker p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:123961122,name=3321889 p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:123961122,name=3321889 p:Worker:name:workp p1:Worker:name:workp p2:Worker:name:workp p:cc p1:cc p2:lios
發現p,p1所有的值都是一致的,當對象p中重置name屬性的值、Worker屬性中name的值後,p、p1、p2中屬性Worker中name屬性值都改變了且值相同,但是p2中的name屬性值沒有變化,下面用圖描述:
p1與p指向堆中的同一塊內存區域,p2雖然與p、p1不是指向同一塊內存區域,但是它們中的Worker屬性都引用同一塊內存區域,其實這就是淺克隆,修改上面clone方法:
@Override protected Object clone() throws CloneNotSupportedException { Person p = (Person) super.clone(); p.worker = (Worker) p.getWorker().clone(); return p; }
再執行,結果如下:
p:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889 p1:toString:com.lios.clone.Person@2401f4c3,hashCode:604107971,Worker:123961122,name=3321889 com.lios.clone.Person@2401f4c3 ===================== p:Worker:name:worker p1:Worker:name:worker p2:Worker:name:worker p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:1982791261,name=3321889 p2:toString:com.lios.clone.Person@4926097b,hashCode:1227229563,Worker:1982791261,name=3321889 p:Worker:name:workp p1:Worker:name:workp p2:Worker:name:worker p:cc p1:cc p2:lios
發現此時p2中屬性Worker中的name屬性值沒有改變,僅僅p、p1中屬性Worker中的name屬性值改變了,圖示:
上面就是深克隆
總結
- 對象被clone必須實現Cloneable接口
- 深克隆需拷貝對象中包含的引用指向的所有對象