Java的clone()方法


1. clone方法簡介

clone方法返回與當前對象的一個副本對象。可以通過操作副本對象而不影響當前對象。

使用clone方法需要實現Cloneable接口。並重寫Object方法中的clone方法。

需要注意的是在clone在Object中是project修飾符。因為所有類都是Object的子類,所以如果不實現clone方法,在類中可以直接使用父類的clone方法,但是其對象在別的類中不能調用clone方法。所以必須重寫clone方法。

如果不實現Cloneable接口,只重寫clone方法,調用則會拋出異常。

Stu類未實現Cloneable接口所以拋出異常

 

2. 淺克隆與深克隆

2.1 淺克隆

看下面一個例子

 1 import java.util.Arrays;
 2 import java.util.HashSet;
 3 import java.util.Scanner;
 4 import java.util.Set;
 5 
 6 public class Test {
 7     
 8     public static void main(String[] args) throws CloneNotSupportedException {
 9         Stu stu = new Stu();
10         stu.name = "Tom";
11         Stu stu1;
12         stu1 = stu;
13         System.out.println(stu==stu1);
14         stu1.name = "LiMing";
15         System.out.println("stu:"+stu.name+" stu1:"+stu1.name);
16         stu1 = (Stu) stu.clone();
17         System.out.println(stu==stu1);
18         stu1.name = "Tom";
19         System.out.println("stu:"+stu.name+" stu1:"+stu1.name);
20     }
21 
22 }
23 class Stu implements Cloneable{
24     String name;
25     @Override
26     protected Object clone() throws CloneNotSupportedException {
27         // TODO Auto-generated method stub
28         return super.clone();
29     }
30     
31 }

Stu類實現了Cloneable接口,並且重寫了clone方法。

首先設stu1變量值等於stu,我們都知道stu1直接指向stu的地址。所以測試stu1==stu時,結果為true,說明兩個地址相同。同時改變stu1的name值為“LiMing”,stu的name值也改為“LiMimg”。

設stu1變量值等於stu.clone(),這時stu1的指向stu對象副本的地址,測試stu1==stu,結果為false,說明兩個地址不同。改變stu1的name值為"Tom",stu因為指向的對象與stu1的指向的對象不同,因此stu的name值並未改變。

測試結果

2.2 深克隆

考慮下面這種情況

學生類包含筆類,這時在使用clone方法。

 1 public class Test {
 2     
 3     public static void main(String[] args) throws CloneNotSupportedException {
 4         Stu stu = new Stu();
 5         stu.name = "Tom";
 6         stu.pen.name = "A";
 7         Stu stu1;
 8         stu1 = (Stu) stu.clone();
 9         System.out.println(stu1.pen==stu.pen);
10         stu1.pen.name = "B";
11         System.out.println("stu1:"+stu1.pen.name+"|stu:"+stu.pen.name);
12     }
13 
14 }
15 class Stu implements Cloneable{
16     String name;
17     Pen pen = new Pen();
18     @Override
19     protected Object clone() throws CloneNotSupportedException {
20         // TODO Auto-generated method stub
21         return super.clone();
22     }
23     
24 }
25 class Pen{
26     String name;
27 }

發現此時stu1.pen的地址與stu.pen的地址相同。所以改變stu1.pen.name的值,stu.pen.name的值也發生了相應的改變。這是因為對於引用類型,clone方法只克隆引用類型的地址。這時就用到了深克隆。

測試結果

深克隆:

 1 public class Test {
 2     
 3     public static void main(String[] args) throws CloneNotSupportedException {
 4         Stu stu = new Stu();
 5         stu.name = "Tom";
 6         stu.pen.name = "A";
 7         Stu stu1;
 8         stu1 = (Stu) stu.clone();
 9         System.out.println(stu1.pen==stu.pen);
10         stu1.pen.name = "B";
11         System.out.println("stu1:"+stu1.pen.name+"|stu:"+stu.pen.name);
12     }
13 
14 }
15 class Stu implements Cloneable{
16     String name;
17     Pen pen = new Pen();
18     @Override
19     protected Object clone() throws CloneNotSupportedException {
20         // TODO Auto-generated method stub
21         Stu temp = (Stu) super.clone();
22         temp.pen = (Pen) pen.clone();
23         return temp;
24     }
25     
26 }
27 class Pen implements Cloneable{
28     String name;
29     @Override
30     protected Object clone() throws CloneNotSupportedException {
31         // TODO Auto-generated method stub
32         return super.clone();
33     }
34 }

此時Pen類也重寫了Cloneable方法。同時在重寫Stu類的clone方法時先克隆Pen,在返回temp,這樣temp中的pen指向克隆后的地址。

運行結果stu1.pen的地址與stu.pen的地址不在相同,改變stu1.pen.name的值而stu.pen.name的值不在改變。stu1.pen對象是一個全新的副本。

測試結果:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM