Java的clone()方法

Posted 来一点音乐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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对象是一个全新的副本。

测试结果:

 

以上是关于Java的clone()方法的主要内容,如果未能解决你的问题,请参考以下文章

GitGit 分支管理 ( 克隆远程分支 | 克隆 master 分支 git clone | 查看远程分支 git branch -a | 克隆远程分支 git checkout -b )(代码片段

JAVA 对象的clone方法实例类型

Java Object对象之clone方法

Java Object对象之clone方法

阿里公约推荐慎用 Object 的 clone 方法来拷贝对象。

Java的clone()方法