注:玩的是JDK1.7版本java
一:Cloneable.java 接口也是標記接口,因此,它沒有任何方法和屬性,實現此接口表示的意思是:能夠調用 Object.java 類的 clone() 方法,進行簡單的屬性到屬性之間的克隆,若是沒有實現此接口的話調用 Object.java 類的 clone() 方法會拋出 java.lang.CloneNotSupportedException 異常。express
另外,若是實現了 Cloneabel.java 接口,一般會複寫 Object.java 的 clone() 方法,由於,在 Object.java 中 clone() 方法是受保護的,因此,須要提供一個public的 clone() 方法。app
package java.lang; /** * A class implements the <code>Cloneable</code> interface to * indicate to the {@link java.lang.Object#clone()} method that it * is legal for that method to make a * field-for-field copy of instances of that class. * <p> * Invoking Object's clone method on an instance that does not implement the * <code>Cloneable</code> interface results in the exception * <code>CloneNotSupportedException</code> being thrown. * <p> * By convention, classes that implement this interface should override * <tt>Object.clone</tt> (which is protected) with a public method. * See {@link java.lang.Object#clone()} for details on overriding this * method. * <p> * Note that this interface does <i>not</i> contain the <tt>clone</tt> method. * Therefore, it is not possible to clone an object merely by virtue of the * fact that it implements this interface. Even if the clone method is invoked * reflectively, there is no guarantee that it will succeed. * * @author unascribed * @see java.lang.CloneNotSupportedException * @see java.lang.Object#clone() * @since JDK1.0 */ public interface Cloneable { }
二:驗證上述結論ide
1)定義一個簡單的類,特地不實現 Cloneabel.java 接口,以下所示:測試
/** * @description:人類 * @author:godtrue * @create:2018-09-09 */ public class Person{/** 請注意這裏,沒有實現 Cloneable 接口 **/ /** * 身份證號 */ private int id; /** * 姓名 */ private String name; /** * 性別 */ private boolean sex; /** * 年齡 */ private int age; /** * *@description: 複寫 Object.java 的克隆方法 *@param *@return: java.lang.Object *@author: godtrue *@createTime: 2018-09-18 *@version: v1.0 */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Person{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", sex=").append(sex==true?"男":"女"); sb.append(", age=").append(age); sb.append('}'); return sb.toString(); } }
2)定義一個測試入口類,以下所示:ui
/** * @description:玩一把Cloneable * @author:godtrue * @create:2018-09-18 */ public class PlayCloneable { /** * *@description: 測試入口,主方法 *@param args *@return: void *@author: godtrue *@createTime: 2018-09-18 *@version: v1.0 */ public static void main(String[] args) throws CloneNotSupportedException{ Person person = genPerson(); System.out.println("person is "+person); Person personTemp = (Person) person.clone(); personTemp.setId(618); personTemp.setName("六一八"); System.out.println("personTemp is "+personTemp); } /** * *@description: 生成 Person 對象信息 *@param *@return: com.godtrue.Person *@author: godtrue *@createTime: 2018-09-18 *@version: v1.0 */ private static Person genPerson(){ Person person = new Person(); person.setId(1111); person.setSex(true); person.setName("雙十一"); person.setAge(2); return person; } }
3)測試的結果以下所示(果真,拋出了對應的異常,側面反映出咱們的結論了:沒實現Cloneable.java接口時,調用 Object.java 類的 clone() 方法會拋出 java.lang.CloneNotSupportedException 異常):this
4)調整 Person.java 類 使其實現 Cloneable.java 接口,而後再實驗下,看看什麼效果,調整的類以下所示:spa
/** * @description:人類 * @author:godtrue * @create:2018-09-09 */ public class Person implements Cloneable{/** 請注意這裏,實現了 Cloneable 接口 **/ /** * 身份證號 */ private int id; /** * 姓名 */ private String name; /** * 性別 */ private boolean sex; /** * 年齡 */ private int age; /** * *@description: 複寫 Object.java 的克隆方法 *@param *@return: java.lang.Object *@author: godtrue *@createTime: 2018-09-18 *@version: v1.0 */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Person{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", sex=").append(sex==true?"男":"女"); sb.append(", age=").append(age); sb.append('}'); return sb.toString(); } }
5)運行結果以下所示(正面反映出了咱們的結論:當實現Cloneable.java接口時,可以正常調用 Object.java 類的 clone() 方法):code
三:爲何會這樣呢?orm
1)先看以下的變種例子,注意 clone() 方法的實現,以下所示
/** * @description:人類 * @author:godtrue * @create:2018-09-09 */ public class Person{/** 請注意這裏,沒有實現 Cloneable 接口 **/ /** * 身份證號 */ private int id; /** * 姓名 */ private String name; /** * 性別 */ private boolean sex; /** * 年齡 */ private int age; /** * *@description: 複寫 Object.java 的克隆方法 *@param *@return: java.lang.Object *@author: godtrue *@createTime: 2018-09-18 *@version: v1.0 */ @Override public Object clone(){ Person copy = new Person(); copy.id = this.id; copy.name = this.name; copy.sex = this.sex; copy.age = this.age; return copy; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { final StringBuilder sb = new StringBuilder("Person{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", sex=").append(sex==true?"男":"女"); sb.append(", age=").append(age); sb.append('}'); return sb.toString(); } }
2)運行結果以下所示,注意,不用處理 java.lang.CloneNotSupportedException 由於,咱們的 Person.java 的 clone() 方法沒用使用 Object.java 的 clone() 方法
3)看一下 Object.java 的 clone() 方法,從註釋中咱們能夠得出以下關鍵信息
3-1)Object.java 的 clone() 方法是一個 native 方法
3-2)經過 Object.java 的 clone() 方法獲取的新對象是一個淺克隆的對象,打個比方:有點相似兩個連體雙胞胎的關係(這個回頭再細說)
3-3)針對沒有實現 Cloneable.java 接口的類,若是複寫了 Object.java 類的 clone() 方法,且經過 Object.java 類的 clone() 方法實現了對象的淺克隆的話,在調用複寫的 clone() 方法的時候,就會拋出 java.lang.CloneNotSupportedException 異常,由於,Object.java 類的 clone() 方法拋出了此異常,因此,對應的應該有捕獲或者再拋出的措施才行,(Object.java 類的 clone() 方法的本地實現我還沒看,猜想,他會先檢查對應的類是否實現了Cloneabe.java接口,若是沒有,則會拋出 java.lang.CloneNotSupportedException 異常,若是實現了,則會進行對對象的淺克隆操做)
3-4)複寫 Object.java 的 clone() 方法,和是否實現 Cloneable.java 接口沒有什麼必然關係,複寫的 clone() 方法的實現,能夠有多種選擇,可是一旦選擇使用 Object.java 類的 clone() 方法來快速實現一個對象的淺克隆的話,就必須實現 Cloneable.java 接口,不然就會拋出 java.lang.CloneNotSupportedException 異常
3-5)至此,咱們也清楚了,Cloneable.java 接口的核心做用在於,可經過 Object.java 類的 clone() 方法進行對象的快速淺克隆,具體實現步驟以下所示:
第一步:實現Cloneable.java接口
第二步:複寫Object.java類的clone()方法,使方法處處可用(public的訪問權限),調用Object.java類的clone()方法快速的淺克隆對象
第三步:若是想進行深克隆,也能夠在淺克隆的基礎上再加工處理
/** * Creates and returns a copy of this object. The precise meaning * of "copy" may depend on the class of the object. The general * intent is that, for any object {@code x}, the expression: * <blockquote> * <pre> * x.clone() != x</pre></blockquote> * will be true, and that the expression: * <blockquote> * <pre> * x.clone().getClass() == x.getClass()</pre></blockquote> * will be {@code true}, but these are not absolute requirements. * While it is typically the case that: * <blockquote> * <pre> * x.clone().equals(x)</pre></blockquote> * will be {@code true}, this is not an absolute requirement. * <p> * By convention, the returned object should be obtained by calling * {@code super.clone}. If a class and all of its superclasses (except * {@code Object}) obey this convention, it will be the case that * {@code x.clone().getClass() == x.getClass()}. * <p> * By convention, the object returned by this method should be independent * of this object (which is being cloned). To achieve this independence, * it may be necessary to modify one or more fields of the object returned * by {@code super.clone} before returning it. Typically, this means * copying any mutable objects that comprise the internal "deep structure" * of the object being cloned and replacing the references to these * objects with references to the copies. If a class contains only * primitive fields or references to immutable objects, then it is usually * the case that no fields in the object returned by {@code super.clone} * need to be modified. * <p> * The method {@code clone} for class {@code Object} performs a * specific cloning operation. First, if the class of this object does * not implement the interface {@code Cloneable}, then a * {@code CloneNotSupportedException} is thrown. Note that all arrays * are considered to implement the interface {@code Cloneable} and that * the return type of the {@code clone} method of an array type {@code T[]} * is {@code T[]} where T is any reference or primitive type. * Otherwise, this method creates a new instance of the class of this * object and initializes all its fields with exactly the contents of * the corresponding fields of this object, as if by assignment; the * contents of the fields are not themselves cloned. Thus, this method * performs a "shallow copy" of this object, not a "deep copy" operation. * <p> * The class {@code Object} does not itself implement the interface * {@code Cloneable}, so calling the {@code clone} method on an object * whose class is {@code Object} will result in throwing an * exception at run time. * * @return a clone of this instance. * @exception CloneNotSupportedException if the object's class does not * support the {@code Cloneable} interface. Subclasses * that override the {@code clone} method can also * throw this exception to indicate that an instance cannot * be cloned. * @see java.lang.Cloneable */ protected native Object clone() throws CloneNotSupportedException;
4)看一下 java.lang.CloneNotSupportedException.java 的存在本意,不實現 Cloneable.java 接口,可是調用了 Object.java 類的 clone() 方法就會拋出此異常了
/** * Thrown to indicate that the <code>clone</code> method in class * <code>Object</code> has been called to clone an object, but that * the object's class does not implement the <code>Cloneable</code> * interface. * <p> * Applications that override the <code>clone</code> method can also * throw this exception to indicate that an object could not or * should not be cloned. * * @author unascribed * @see java.lang.Cloneable * @see java.lang.Object#clone() * @since JDK1.0 */ public class CloneNotSupportedException extends Exception { private static final long serialVersionUID = 5195511250079656443L; /** * Constructs a <code>CloneNotSupportedException</code> with no * detail message. */ public CloneNotSupportedException() { super(); } /** * Constructs a <code>CloneNotSupportedException</code> with the * specified detail message. * * @param s the detail message. */ public CloneNotSupportedException(String s) { super(s); } }