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 )(代码片段