克隆,大家都听过,JAVA克隆实现的大致意思就是实现类的克隆,为什么JAVA要实现克隆了,那就要说到JAVA里面的指针,引用
我先贴一段测试代码,再慢慢解释
package com.linpyi.clone;
public class TestClone {
public static void main(String[] args){
TestBean bean1= new TestBean();
//初始化给bean赋值
bean1.setId(1);
bean1.setName("name1");
//打印出赋完值的bean
System.out.println("bean1.id=="+bean1.getId()+",bean1.name=="+bean1.getName());
System.out.println("******modify******");
//实例化bean2
TestBean bean2 = new TestBean();
//把bean1赋给bean2,实际上这赋的是地址
bean2=bean1;
System.out.println("modify before bean1.id=="+bean1.getId()+",bean1.name=="+bean1.getName());
System.out.println("modify before bean2.id=="+bean2.getId()+",bean2.name=="+bean2.getName());
//修改bean1的值
bean1.setId(2);
bean1.setName("name2");
//打印出bean1和bean2的值,发现bean2的值随bean1改变而改变,验证上面赋的是地址
System.out.println("modify after bean1.id=="+bean1.getId()+",bean1.name=="+bean1.getName());
System.out.println("modify after bean2.id=="+bean2.getId()+",bean2.name=="+bean2.getName());
System.out.println("\r\n***************clone1****************\r\n");
//实例化bean3
TestBean bean3 = new TestBean();
//使用克隆方法给bean3赋值
bean3=(TestBean)bean1.clone();
//打印未修改bean1前bean1,bean2,bean3的值
System.out.println("clone before bean1.id=="+bean1.getId()+",bean1.name=="+bean1.getName());
System.out.println("clone after bean2.id=="+bean2.getId()+",bean2.name=="+bean2.getName());
System.out.println("clone before bean3.id=="+bean3.getId()+",bean3.name=="+bean3.getName());
//修改bean1的值
bean1.setId(3);
bean1.setName("name3");
//打印修改后bean的值,发现只有bean3使用克隆后的bean未改变值
System.out.println("clone after bean1.id=="+bean1.getId()+",bean1.name=="+bean1.getName());
System.out.println("clone after bean2.id=="+bean2.getId()+",bean2.name=="+bean2.getName());
System.out.println("clone after bean3.id=="+bean3.getId()+",bean3.name=="+bean3.getName());
System.out.println("\r\n***************clone2**************\r\n");
//实现影子克隆和深度克隆,以下代码实现了深度克聋
TestBean bean4 = new TestBean();
bean4.setId(4);
bean4.setName("name4");
System.out.println("clone bean4.id=="+bean4.getId()+",bean4.name=="+bean4.getName()+",bean4.bean.value=="+bean4.bean.i);
TestBean bean5 = new TestBean();
bean5=bean4;
System.out.println("clone bean5.id=="+bean5.getId()+",bean5.name=="+bean5.getName()+",bean5.bean.value=="+bean5.bean.i);
TestBean bean6 = new TestBean();
bean6=(TestBean)bean4.clone();
System.out.println("clone before bean6.id=="+bean6.getId()+",bean5.name=="+bean6.getName()+",bean6.bean.value=="+bean6.bean.i);
bean6.setId(6);
bean6.setName("name6");
bean6.bean.setValue();
System.out.println("clone after bean4.id=="+bean4.getId()+",bean4.name=="+bean4.getName()+",bean4.bean.value=="+bean4.bean.i);
System.out.println("clone after bean5.id=="+bean5.getId()+",bean5.name=="+bean5.getName()+",bean5.bean.value=="+bean5.bean.i);
System.out.println("clone after bean6.id=="+bean6.getId()+",bean5.name=="+bean6.getName()+",bean6.bean.value=="+bean6.bean.i);
System.out.println("\r\n***************clone3**************\r\n");
//以下是对克隆String 和 StringBuffer的测试代码
TestBean bean7 = new TestBean();
bean7.setName("nam7");
bean7.pwd="hello world.";
bean7.sb = new StringBuffer("hello world.");
bean7.sum=10;
System.out.println("clone after bean7.pwd=="+bean7.pwd+", bean7.sb=="+bean7.sb+" bean7.sum=="+bean7.sum+", bean7.name=="+bean7.getName());
TestBean bean8 = new TestBean();
bean8=(TestBean)bean7.clone();
System.out.println("clone after bean8.pwd=="+bean8.pwd+", bean8.sb=="+bean8.sb+" bean8.sum=="+bean8.sum+", bean7.name=="+bean8.getName());
//这里实现了对String的克隆,如果改为bean8.pwd=bean8.pwd.substring(0,5)才会有效果,这又是一个赋值,达到假效果;单纯的bean8.pwd.substring(0,5)不会出现任何效果,所以对String和StringBuffer的克隆比较特别
bean8.pwd.substring(0,5);
//修改后,bean7的值也改变了
bean8.sb.append("this is world.");
//而int型的确没有改变
bean8.sum-=20;
//用set方法会就等于重新给他赋值,也可以实现clone的效果
bean8.setName("name8");
System.out.println("clone before bean7.pwd=="+bean7.pwd+", bean7.sb=="+bean7.sb+" bean7.sum=="+bean7.sum+", bean7.name=="+bean7.getName());
System.out.println("clone before bean8.pwd=="+bean8.pwd+", bean8.sb=="+bean8.sb+" bean8.sum=="+bean8.sum+", bean8.name=="+bean8.getName());
}
}
javaBean.java
package com.linpyi.clone;
/**
* 测试JAVABEAN
* @author work
*
*/
public class TestBean implements Cloneable{
private int id;
private String name;
public StringBuffer sb;//公有的变量,测试stringbuffer
public String pwd;//公有变量,测试string
public int sum;//公有变量,测试int
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 TestBean1 bean = new TestBean1();
public Object clone(){
TestBean o = null;
try{
o = (TestBean)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
o.bean = (TestBean1)bean.clone();
return o;
}
}
TestBean1
package com.linpyi.clone;
/**
* bean1主要测试深度克隆
* @author work
*
*/
public class TestBean1 implements Cloneable{
public int i=1;
public TestBean1(){
}
public void setValue(){
i=2;
}
public Object clone(){
TestBean1 o = null;
try{
o = (TestBean1)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
运行结果
bean1.id==1,bean1.name==name1
******modify******
modify before bean1.id==1,bean1.name==name1
modify before bean2.id==1,bean2.name==name1
modify after bean1.id==2,bean1.name==name2
modify after bean2.id==2,bean2.name==name2
***************clone1****************
clone before bean1.id==2,bean1.name==name2
clone after bean2.id==2,bean2.name==name2
clone before bean3.id==2,bean3.name==name2
clone after bean1.id==3,bean1.name==name3
clone after bean2.id==3,bean2.name==name3
clone after bean3.id==2,bean3.name==name2
***************clone2**************
clone bean4.id==4,bean4.name==name4,bean4.bean.value==1
clone bean5.id==4,bean5.name==name4,bean5.bean.value==1
clone before bean6.id==4,bean5.name==name4,bean6.bean.value==1
clone after bean4.id==4,bean4.name==name4,bean4.bean.value==1
clone after bean5.id==4,bean5.name==name4,bean5.bean.value==1
clone after bean6.id==6,bean5.name==name6,bean6.bean.value==2
***************clone3**************
clone after bean7.pwd==hello world., bean7.sb==hello world. bean7.sum==10, bean7.name==nam7
clone after bean8.pwd==hello world., bean8.sb==hello world. bean8.sum==10, bean7.name==nam7
clone before bean7.pwd==hello world., bean7.sb==hello world.this is world. bean7.sum==10, bean7.name==nam7
clone before bean8.pwd==hello world., bean8.sb==hello world.this is world. bean8.sum==-10, bean8.name==name8
1.首先我们先测试为什么要使用克隆,作为测试用的克隆,不需要使用TestBean1这个类,TestBean也做相应修改,注释掉
克隆方法里面的 o.bean = (TestBean1)bean.clone();,测试克隆我们只用到
private int id;
private String name;
和他们的set方法
具体代码如下
package com.linpyi.clone;
/**
* 测试JAVABEAN
* @author work
*
*/
public class TestBean implements Cloneable{
private int id;
private String name;
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 Object clone(){
TestBean o = null;
try{
o = (TestBean)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
// o.bean = (TestBean1)bean.clone();
return o;
}
}
我们实例化一个TestBean(下面称bean)bean1 然后给他赋初始值,再实例化一个bean2,把bean2=bean1,
打印2个bean的值,发现值是一样的,
接着修改bean1的值,发现2个bean都修改值了,在bean2=bean1的时候实际上指向同一个地址
有很多情况下,我们需要=,但是又需要修改其中的值,因为2个bean我们都需要,当然你可以重新把bean的值打出来再赋给
新的bean,但这样麻烦,所以就产生克隆的概念
说说怎么克隆:
比较经典的方法,其中TestBean可以改为你要克隆的类名
public Object clone(){
TestBean o = null;
try{
o = (TestBean)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
o.bean = (TestBean1)bean.clone();
return o;
}
在要实现的类上实现implements Cloneable接口
implements Cloneable接口是不包含任何方法的!其实这个接口仅仅是一个标志,而且这个标志也仅仅是针对Object
类中clone()方法的,如果clone类没有实现Cloneable接口,并调用了Object的clone()方法(也就是调用
super.Clone()方法),那么Object的clone()方法就会抛出CloneNotSupportedException异常。
这个接口属于java.lang包,java.lang包已经被缺省的导入类中,所以不需要写成java.lang.Cloneable。另一个值得
请注意的是重载了clone()方法。最后在clone()方法中调用了super.clone(),这也意味着无论clone类的继承结构是什
么样的,super.clone()直接或间接调用了java.lang.Object类的clone()方法。
有了以上的介绍,我们开始测试
首先实现bean3,使用bean3=(TestBean)bean1.clone();方法给bean赋值
其次接着像上面那样修改bean1的值,结果可以发现,随着bean1的修改,bean2的值也改变了,bean3的值确没有改变
说明克隆成功
clone after bean1.id==3,bean1.name==name3
clone after bean2.id==3,bean2.name==name3
clone after bean3.id==2,bean3.name==name2
2.我们来说说影子克隆
实现影子克隆不能使用上面的代码,因为我已经实现了深度克隆,我再介绍下代码
首先我们在上面实现了简单的克隆测试,也了解了JAVA克隆,现在我们的bean中嵌套bean
也就是使用了TestBean1这个类,实现影子克隆的TestBean1的代码如下,和上面有点不一样,
package com.linpyi.clone;
/**
* bean1主要测试深度克隆
* @author work
*
*/
public class TestBean1{
public int i=1;
public TestBean1(){
}
public void setValue(){
i=2;
}
}
TestBean的代码如下
package com.linpyi.clone;
/**
* 测试JAVABEAN
* @author work
*
*/
public class TestBean implements Cloneable{
private int id;
private String name;
public StringBuffer sb;//公有的变量,测试stringbuffer
public String pwd;//公有变量,测试string
public int sum;//公有变量,测试int
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 TestBean1 bean = new TestBean1();//其实就是多了一个bean
public Object clone(){
TestBean o = null;
try{
o = (TestBean)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
然后我们开始测试,使用上面的clone2的代码测试
System.out.println("\r\n***************clone2**************\r\n");
//实现影子克隆和深度克隆
TestBean bean4 = new TestBean();
bean4.setId(4);
bean4.setName("name4");
System.out.println("clone bean4.id=="+bean4.getId()+",bean4.name=="+bean4.getName()+",bean4.bean.value=="+bean4.bean.i);
TestBean bean5 = new TestBean();
bean5=bean4;
System.out.println("clone bean5.id=="+bean5.getId()+",bean5.name=="+bean5.getName()+",bean5.bean.value=="+bean5.bean.i);
TestBean bean6 = new TestBean();
bean6=(TestBean)bean4.clone();
System.out.println("clone before bean6.id=="+bean6.getId()+",bean5.name=="+bean6.getName()+",bean6.bean.value=="+bean6.bean.i);
bean6.setId(6);
bean6.setName("name6");
bean6.bean.setValue();//对TestBean1进行赋值
System.out.println("clone after bean4.id=="+bean4.getId()+",bean4.name=="+bean4.getName()+",bean4.bean.value=="+bean4.bean.i);
System.out.println("clone after bean5.id=="+bean5.getId()+",bean5.name=="+bean5.getName()+",bean5.bean.value=="+bean5.bean.i);
System.out.println("clone after bean6.id=="+bean6.getId()+",bean5.name=="+bean6.getName()+",bean6.bean.value=="+bean6.bean.i);
其实原理和上面的克垄一样,只是多了一个对TestBean1中i的赋值
运行结果
***************clone2**************
clone bean4.id==4,bean4.name==name4,bean4.bean.value==1
clone bean5.id==4,bean5.name==name4,bean5.bean.value==1
clone before bean6.id==4,bean5.name==name4,bean6.bean.value==1
clone after bean4.id==4,bean4.name==name4,bean4.bean.value==2
clone after bean5.id==4,bean5.name==name4,bean5.bean.value==2
clone after bean6.id==6,bean5.name==name6,bean6.bean.value==2
我们实现了一个bean4和bean5,对bean4实行赋值,把bean5=bean4,打印出来,很明显2个值是一样的
接着我们实现bean6,对bean6实行对bean4的克聋bean6=(TestBean)bean4.clone();
打印出bean6的值
clone before bean6.id==4,bean5.name==name4,bean6.bean.value==1
和bean4应该是一样的
接着我们改变bean6的值
bean6.setId(6);
bean6.setName("name6");
bean6.bean.setValue();//把i的值赋为2
打印出来
clone after bean4.id==4,bean4.name==name4,bean4.bean.value==2
clone after bean5.id==4,bean5.name==name4,bean5.bean.value==2
clone after bean6.id==6,bean5.name==name6,bean6.bean.value==2
发现bean6的id 和name改变了,而bean6中的TestBean1的value值改变了,连bean4和bean5的value一起改变了,
说明克隆失败,为什么了,因为,这只是实行了影子克隆,对深一步的代码没实现克隆,也就是深度克隆
3.深度克隆,
有了上面影子克隆,现在解决上面没解决的问题,
首先,把TestBean1中也实现克隆方法
package com.linpyi.clone;
/**
* bean1主要测试深度克隆
* @author work
*
*/
public class TestBean1 implements Cloneable{
public int i=1;
public TestBean1(){
}
public void setValue(){
i=2;
}
public Object clone(){
TestBean1 o = null;
try{
o = (TestBean1)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
在TestBean中加入o.bean = (TestBean1)bean.clone();
package com.linpyi.clone;
/**
* 测试JAVABEAN
* @author work
*
*/
public class TestBean implements Cloneable{
private int id;
private String name;
public StringBuffer sb;//公有的变量,测试stringbuffer
public String pwd;//公有变量,测试string
public int sum;//公有变量,测试int
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 TestBean1 bean = new TestBean1();
public Object clone(){
TestBean o = null;
try{
o = (TestBean)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
o.bean = (TestBean1)bean.clone();
return o;
}
}
原理应该和上面的一样,只是多了一个克隆
运行结果
***************clone2**************
clone bean4.id==4,bean4.name==name4,bean4.bean.value==1
clone bean5.id==4,bean5.name==name4,bean5.bean.value==1
clone before bean6.id==4,bean5.name==name4,bean6.bean.value==1
clone after bean4.id==4,bean4.name==name4,bean4.bean.value==1
clone after bean5.id==4,bean5.name==name4,bean5.bean.value==1
clone after bean6.id==6,bean5.name==name6,bean6.bean.value==2
实现了影子克隆和深度克隆,克隆也有例外,那就是String和StringBuffer也就是我们克隆3做的事
3.关于String和StringBuffer
String和StringBuffer是比较特殊的类型
同样的代码
System.out.println("\r\n***************clone3**************\r\n");
//以下是对克隆String 和 StringBuffer的测试代码
TestBean bean7 = new TestBean();
bean7.setName("name7");
bean7.pwd="hello world.";
bean7.sb = new StringBuffer("hello world.");
bean7.sum=10;
System.out.println("clone after bean7.pwd=="+bean7.pwd+", bean7.sb=="+bean7.sb+" bean7.sum=="+bean7.sum+", bean7.name=="+bean7.getName());
TestBean bean8 = new TestBean();
bean8=(TestBean)bean7.clone();
System.out.println("clone after bean8.pwd=="+bean8.pwd+", bean8.sb=="+bean8.sb+" bean8.sum=="+bean8.sum+", bean7.name=="+bean8.getName());
//这里实现了对String的克隆,如果改为bean8.pwd=bean8.pwd.substring(0,5)才会有效果,这又是一个赋值,达到假效果;单纯的bean8.pwd.substring(0,5)不会出现任何效果,所以对String和StringBuffer的克隆比较特别
bean8.pwd.substring(0,5);
//修改后,bean7的值也改变了
bean8.sb.append("this is world.");
//而int型的确没有改变
bean8.sum-=20;
//用set方法会就等于重新给他赋值,也可以实现clone的效果
bean8.setName("name8");
System.out.println("clone before bean7.pwd=="+bean7.pwd+", bean7.sb=="+bean7.sb+" bean7.sum=="+bean7.sum+", bean7.name=="+bean7.getName());
System.out.println("clone before bean8.pwd=="+bean8.pwd+", bean8.sb=="+bean8.sb+" bean8.sum=="+bean8.sum+", bean8.name=="+bean8.getName());
在bean中增加
public StringBuffer sb;//公有的变量,测试stringbuffer
public String pwd;//公有变量,测试string
public int sum;//公有变量,测试int
利用公有的,是为了方便测试,不用set方法
实例话bean7给bean7的setName,pwd,StringBuffer,int赋值
使用克隆方法
最后打印出来会发现只有int和setName的值实现了克隆方法,
直接对String和StringBuffer的操作,没有效果,会改变成原来的bean7
如果是bean8.pwd=bean8.pwd.substring(0,5),重新给他赋值的话就可以实现,当然这样属于假克隆
应该知道的是在Java中所有的基本数据类型都有一个相对应的类,象Integer类对应int类型,Double类对应double类型
等等,这些类也与String类相同,都是不可以改变的类。也就是说,这些的类中的所有方法都是不能改变其自身的值的。这
也让我们在编clone类的时候有了一个更多的选择。同时我们也可以把自己的类编成不可更改的类。当然如果想实现就像上
面那样实现辅值,也许能实现克隆.但是StringBuffer在jdk中的不属于final,所以.....
写晕了,