首先,看一下源碼:
1 public class Object {
2 protected native Object clone() throws CloneNotSupportedException;
3 }
由源代碼我們會發現:
第一:Object類的clone()方法是一個native方法,native方法的效率一般來說都是遠高於Java中的非native方法。這也解釋了爲什麼要用Object中clone()方法而不是先new一個類,然後把原始對象中的信息複製到新對象中,雖然這也實現了clone功能。(JNI是Java Native Interface的 縮寫。從Java 1.1開始,Java Native Interface (JNI)標準成爲java平臺的一部分,它允許Java代碼和其他語言寫的代碼進行交互。JNI一開始是爲了本地已編譯語言,尤其是C和C++而設計的,但是它並不妨礙你使用其他語言,只要調用約定受支持就可以了。使用java與本地已編譯的代碼交互,通常會喪失平臺可移植性。但是,有些情況下這樣做是可以接受的,甚至是必須的,比如,使用一些舊的庫,與硬件、操作系統進行交互,或者爲了提高程序的性能。JNI標準至少保證本地代碼能工作在任何Java 虛擬機實現下。)
第二:Object類中的 clone()方法被protected修飾符修飾。這也意味着如果要應用 clone()方 法,必須繼承Object類,在 Java中所有的類是缺省繼承 Object類的,也就不用關心這點了。然後重載 clone()方法。還有一點要考慮的是爲了讓其它類能調用這個 clone類的 clone()方法,重載之後要把 clone()方法的屬性設置爲 public。
第三:Object.clone()方法返回一個Object對象。我們必須進行強制類型轉換才能得到我們需要的類型。
淺層複製與深層複製概念:
淺層複製: 被複制的對象的所有成員屬性都有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺層複製僅僅複製所考慮的對象,而不復制它所引用的對象。(概念不好理解,請結合下文的示例去理解)
深層複製:被複制對象的所有變量都含有與原來的對象相同的值,除去那些引用其他對象的變量。那些引用其他對象的變量將指向被複制過的新對象,而不是原有的那些被引用的對象。換言之,深層複製要複製的對象引用的對象都複製一遍。
Java中對象的克隆
1)在派生類中實現Cloneable藉口。
2)爲了獲取對象的一份拷貝,我們可以利用Object類的clone方法。
3)在派生類中覆蓋積累的clone方法,聲明爲public。
4)在派生類的clone方法中,調用super.clone()。
實現Cloneable接口
首先,看一下源碼:
1 public interface Cloneable { 2 }
我們奇怪的發現Cloneable竟然是空的,那麼我們爲什麼要實現Cloneable接口呢?其實Cloneable接口僅僅是一個標誌,而且這個標誌也僅僅是針對 Object類中 clone()方法的,如果 clone 類沒有實現 Cloneable 接口,並調用了 Object 的 clone() 方法(也就是調用了 super.Clone() 方法),那麼Object 的 clone() 方法就會拋出 CloneNotSupportedException 異常。
程序示例分析:
1 public class Person { 2 private String name; 3 private int age; 4 public Person(){} 5 public Person(String name,int age){ 6 this.name=name; 7 this.age=age; 8 } 9 public Object clone(){ 10 Object o=null; 11 try { 12 o=super.clone(); 13 } catch (CloneNotSupportedException e) { 14 e.printStackTrace(); 15 } 16 return o; 17 } 18 public String getName() { 19 return name; 20 } 21 public void setName(String name) { 22 this.name = name; 23 } 24 public int getAge() { 25 return age; 26 } 27 public void setAge(int age) { 28 this.age = age; 29 } 30 }
1 public class PersonTest { 2 public static void main(String[] args) { 3 Person p1=new Person("zhangsan",18); 4 Person p2=(Person)p1.clone(); 5 p2.setName("lis"); 6 p2.setAge(20); 7 System.out.println("name=" 8 +p1.getName()+",age="+p1.getAge()); 9 //修改p2後,沒有對p1產生影響。 10 } 11 }
說明:
1)爲什麼我們在派生類中覆蓋Object的clone()方法時,一定要調用super.clone()呢?在運行時刻,Object中的clone()識別你要複製的是哪一個對象,然後爲此對象分配空間,並進行對象的複製,將原始對象的內容一一複製到新對象的存儲空間中。
2)繼承自java.lang.Object.clone()方法是淺層複製。一下代碼可以證明之:
1 public class Student implements Cloneable { 2 private String name; 3 private int age; 4 private Professor pro; 5 public Student(){} 6 public Student(String name,int age,Professor pro){ 7 this.name=name; 8 this.age=age; 9 this.pro=pro; 10 } 11 public Object clone(){ 12 Object o=null; 13 try { 14 //Object中的clone()識別出你要複製的是哪一個對象。 15 o=super.clone(); 16 } catch (CloneNotSupportedException e) { 17 System.out.println(e.toString()); 18 } 19 return o; 20 } 21 public String getName() { 22 return name; 23 } 24 public void setName(String name) { 25 this.name = name; 26 } 27 public int getAge() { 28 return age; 29 } 30 public void setAge(int age) { 31 this.age = age; 32 } 33 public Professor getPro() { 34 return pro; 35 } 36 public void setPro(Professor pro) { 37 this.pro = pro; 38 } 39 } 40 class Professor{ 41 private String name; 42 private int age; 43 public Professor(){} 44 public Professor(String name,int age){ 45 this.name=name; 46 this.age=age; 47 } 48 public String getName() { 49 return name; 50 } 51 public void setName(String name) { 52 this.name = name; 53 } 54 public int getAge() { 55 return age; 56 } 57 public void setAge(int age) { 58 this.age = age; 59 } 60 }
1 public class StudentTest { 2 public static void main(String[] args) { 3 Professor p=new Professor("wangwu",50); 4 Student s1=new Student("zhangsan",18,p); 5 Student s2=(Student)s1.clone(); 6 s2.getPro().setName("maer"); 7 s2.getPro().setAge(40); 8 System.out.println("name="+s1.getPro().getName() 9 +",age="+s1.getPro().getAge()); 10 //name=maer,age=40 11 } 12 }
那麼我們如何實現深層複製的克隆,即在修改s2.Professor時不影響s1.Professor?代碼改進如下:
1 public class Student implements Cloneable { 2 private String name; 3 private int age; 4 Professor pro; 5 public Student(){} 6 public Student(String name,int age,Professor pro){ 7 this.name=name; 8 this.age=age; 9 this.pro=pro; 10 } 11 public Object clone(){ 12 Student o=null; 13 try { 14 //Object中的clone()識別出你要複製的是哪一個對象。 15 o=(Student)super.clone(); 16 } catch (CloneNotSupportedException e) { 17 System.out.println(e.toString()); 18 } 19 o.pro=(Professor)pro.clone(); 20 return o; 21 } 22 public String getName() { 23 return name; 24 } 25 public void setName(String name) { 26 this.name = name; 27 } 28 public int getAge() { 29 return age; 30 } 31 public void setAge(int age) { 32 this.age = age; 33 } 34 public Professor getPro() { 35 return pro; 36 } 37 public void setPro(Professor pro) { 38 this.pro = pro; 39 } 40 } 41 class Professor implements Cloneable{ 42 private String name; 43 private int age; 44 public Professor(){} 45 public Professor(String name,int age){ 46 this.name=name; 47 this.age=age; 48 } 49 public Object clone(){ 50 Object o=null; 51 try { 52 o=super.clone(); 53 } catch (CloneNotSupportedException e) { 54 e.printStackTrace(); 55 } 56 return o; 57 } 58 public String getName() { 59 return name; 60 } 61 public void setName(String name) { 62 this.name = name; 63 } 64 public int getAge() { 65 return age; 66 } 67 public void setAge(int age) { 68 this.age = age; 69 } 70 }
public class StudentTest { public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.getPro().setName("maer"); s2.getPro().setAge(40); System.out.println("name="+s1.getPro().getName() +",age="+s1.getPro().getAge()); //name=wangwu,age=50 } }