本文共 5559 字,大约阅读时间需要 18 分钟。
java支持我们对一个对象进行克隆,那么什么是克隆?
1、什么是克隆?
Java中的克隆分为深克隆和浅克隆
浅克隆:仅仅复制它所考虑的对象,而不复制它所引用的对象。
深克隆:不仅要复制它所考虑的对象,而且还要复制它所引用的对象。
2、为什么要克隆?
引入问题1:为什么要克隆,直接new一个对象不好吗?
new出来的对象,该对象的属性值都是初始化的时候的值。
克隆出来的对象,该对象的属性值可能包含一些已经修改的属性值。
所以,如果需要一个新的对象来保存当前对象的状态的时候,就需要克隆。
引入问题2:既然克隆就是保存当前对象的状态,那么可以将该对象的属性一个一个的复制给new出来的新对象吗?
当然可以,问题是一个个赋值太繁琐。然后效率也不高。而克隆clone是一个native方法,在底层实现的,效率高。
3、如何实现克隆?
在Java中,数据类型分为基本数据类型和引用数据类型
基本数据类型分为:byte, char, int , float ,double ,short , long ,boolean这几种
引用数据类型分为:数组array 、接口interface 、类class等
而深克隆和浅克隆的区别在于:是否支持引用类型的成员变量的复制。
3.1、如何实现浅克隆?
浅克隆一般比较简单,实现步骤如下:
步骤1:被复制的类实现Clonenable接口
步骤2:覆盖clone()方法,方法修饰符为public,在该方法中调用super.clone()方法就可以得到需要复制的对象
代码如下:
1、新建实体类StudenVO,该类需要被克隆,可以实现Cloneable接口
package com.cn.vo;/** * 该实体类需要被克隆,需要实现Cloneable接口 * */public class StudentVO implements Cloneable { private String stuName; //学生姓名 /** * 覆盖的clone方法,注意此处将 protected改为public * */ @Override public Object clone() throws CloneNotSupportedException { StudentVO studentVO=null; try{ //调用super.clone方法进行克隆 studentVO=(StudentVO) super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return studentVO; } //属性get和set方法 public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; }}2、测试
package com.cn.clone;import com.cn.vo.StudentVO;/** * 浅克隆测试 * */public class Test { public static void main(String[] args) throws CloneNotSupportedException { //new方式实例化一个类 StudentVO stu1= new StudentVO(); //为类的属性复制 stu1.setStuName("Tom"); //克隆一个类 StudentVO stu2=(StudentVO) stu1.clone(); System.out.println("学生1"+stu1.getStuName()); System.out.println("学生2"+stu2.getStuName()); //检查这两个对象是否是同一个对象 System.out.println(stu1==stu2); } }
结果显示:
结果证明:通过stu1.clone()可以克隆一个对象stu2,stu1和stu2不是同一个对象,即克隆对象和原对象不是同一个对象。
下面我们再做个测试,修改stuName的属性值为Lucy,然后再观察一下 ,代码如下:
package com.cn.clone;import com.cn.vo.ClazzVO;import com.cn.vo.StudentVO;/** * 浅克隆测试 * */public class Test { public static void main(String[] args) throws CloneNotSupportedException { //实例化一个班级类 ClazzVO claVO=new ClazzVO(); claVO.setClazzName("六年级一班"); //new方式实例化一个学生类 StudentVO stu1= new StudentVO(); //为类的属性复制 stu1.setStuName("Tom"); stu1.setClaVO(claVO); //检查这两个对象是否是同一个对象 stu2.setStuName("Lucy"); System.out.println("学生1:"+stu1.getStuName()); System.out.println("学生2:"+stu2.getStuName()); } }结果显示:
修改stu2的name不会影响stu1的name,再次证明克隆后的对象与被克隆的对象不是同一个对象
3.2、如何实现深克隆?
深克隆是一个稍微复杂的克隆
1、创建一个学生类StudentVO和一个班级类ClazzVO
package com.cn.vo;/** * 该实体类需要被克隆,需要实现Cloneable接口 * */public class StudentVO implements Cloneable { private String stuName; //学生姓名 private ClazzVO claVO; //学生所在班级 /** * 覆盖的clone方法,注意此处将 protected改为public * */ @Override public Object clone() throws CloneNotSupportedException { StudentVO studentVO=null; try{ //调用super.clone方法进行克隆 studentVO=(StudentVO) super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return studentVO; } //属性get和set方法 public String getStuName() { return stuName; } public void setStuName(String stuName) { this.stuName = stuName; } public ClazzVO getClaVO() { return claVO; } public void setClaVO(ClazzVO claVO) { this.claVO = claVO; } }
package com.cn.vo;/** * 班级实体类 * */public class ClazzVO { private String clazzName; //班级名称 //get和set方法 public String getClazzName() { return clazzName; } public void setClazzName(String clazzName) { this.clazzName = clazzName; }}2、测试
package com.cn.clone;import com.cn.vo.ClazzVO;import com.cn.vo.StudentVO;/** * 浅克隆测试 * */public class Test { public static void main(String[] args) throws CloneNotSupportedException { //实例化一个班级类 ClazzVO claVO=new ClazzVO(); claVO.setClazzName("六年级一班"); //new方式实例化一个学生类 StudentVO stu1= new StudentVO(); //为类的属性复制 stu1.setStuName("Tom"); stu1.setClaVO(claVO); //克隆一个类 StudentVO stu2=(StudentVO) stu1.clone(); System.out.println("学生1:"+stu1.getStuName()+"所属班级:"+stu1.getClaVO().getClazzName()); System.out.println("学生2:"+stu2.getStuName()+"所属班级:"+stu2.getClaVO().getClazzName()); } }结果显示:
结果证明:对象确实被克隆成功了
但是还存在一个问题,此时修改stu2的班级属性为五年级三班,再次打印结果
代码如下:
package com.cn.clone;import com.cn.vo.ClazzVO;import com.cn.vo.StudentVO;/** * 浅克隆测试 * */public class Test { public static void main(String[] args) throws CloneNotSupportedException { //实例化一个班级类 ClazzVO claVO=new ClazzVO(); claVO.setClazzName("六年级一班"); //new方式实例化一个学生类 StudentVO stu1= new StudentVO(); //为类的属性复制 stu1.setStuName("Tom"); stu1.setClaVO(claVO); //克隆一个类 StudentVO stu2=(StudentVO) stu1.clone(); claVO.setClazzName("五年级三班"); System.out.println("学生1:"+stu1.getStuName()+"所属班级:"+stu1.getClaVO().getClazzName()); System.out.println("学生2:"+stu2.getStuName()+"所属班级:"+stu2.getClaVO().getClazzName()); } }结果显示:
结果证明:修改stu2的属性,stu1的属性也会被修改,这样就存在很大的问题
将班级实体类克隆,代码如下:
package com.cn.vo;/** * 班级实体类 * */public class ClazzVO implements Cloneable { private String clazzName; //班级名称 //get和set方法 public String getClazzName() { return clazzName; } public void setClazzName(String clazzName) { this.clazzName = clazzName; } @Override public Object clone() throws CloneNotSupportedException { ClazzVO clazzVO=null; try{ clazzVO=(ClazzVO) super.clone(); }catch(Exception e){ e.printStackTrace(); } return clazzVO; } }在studentVO作如下修改:
@Override public Object clone() throws CloneNotSupportedException { StudentVO studentVO=null; try{ //调用super.clone方法进行克隆 studentVO=(StudentVO) super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } studentVO.claVO=(ClazzVO) claVO.clone(); return studentVO; }测试结果如下:
结果证明:修改stu1的引用类型的变量时,不会对克隆对象产生影响